Skip to content

fix(pgcopy): return typed error instead of panicking on extra columns from query:#435

Open
SAY-5 wants to merge 1 commit intoGreenmaskIO:mainfrom
SAY-5:fix/pgcopy-tuple-size-mismatch-432
Open

fix(pgcopy): return typed error instead of panicking on extra columns from query:#435
SAY-5 wants to merge 1 commit intoGreenmaskIO:mainfrom
SAY-5:fix/pgcopy-tuple-size-mismatch-432

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 21, 2026

What

Fixes #432.

pgcopy.(*Row).Decode walked past the end of columnPos whenever the COPY stream contained more columns than the row was constructed for. The dump goroutine then crashed with:

panic: runtime error: index out of range [5] with length 5
github.com/greenmaskio/greenmask/internal/db/postgres/pgcopy.(*Row).Decode

This fired any time a transformation's query: selected extra columns beyond the table's declared schema.

Fix

Added an explicit length check on the fixed-size path: if a non-dynamic row sees idx >= len(columnPos), return a new ErrTupleSizeMismatch sentinel wrapped with the offending byte offset so the caller can surface a useful message. The dynamic path (UseDynamicSize) is unchanged.

(*TransformationPipeline).Dump already wraps Decode errors with error decoding copy line: %w, so the existing error path carries the message all the way out without any code changes at the call site.

Tests

Added TestDecode_extraColumnsTupleSizeMismatch: constructs a 2-column row, feeds it 5 columns over the wire, asserts ErrTupleSizeMismatch is returned. On master this panics; with the fix it returns the typed error.

Verification

Locally on macOS, go 1.26.2:

  • gofmt -s -l internal/db/postgres/pgcopy/: clean
  • go vet ./internal/db/postgres/pgcopy/...: clean
  • go test -race -count=1 ./internal/db/postgres/pgcopy/...: pass

Closes #432

(*Row).Decode walked past the end of columnPos whenever the COPY stream
contained more columns than the row was constructed for, crashing the
dump goroutine with 'panic: runtime error: index out of range'. This
fired in real workloads any time a transformation's 'query:' selected
extra columns beyond the table's declared schema.

Add an explicit length check on the fixed-size path: if a non-dynamic
row sees idx >= len(columnPos), return a new ErrTupleSizeMismatch
sentinel wrapped with the offending byte offset so the caller can
surface a useful message. The dynamic path is unchanged.

Add a regression test that constructs a 2-column row and feeds it 5
columns over the wire; on master the test panics, with the fix it
returns ErrTupleSizeMismatch.

Closes GreenmaskIO#432

Signed-off-by: SAY-5 <[email protected]>
@wwoytenko
Copy link
Copy Markdown
Member

Hi! Thank you for your contribution.

Could you provide a config that can reproduce a behavior related to this change? So I could test it in playground.

@wwoytenko
Copy link
Copy Markdown
Member

Have you tested the whole dump/restore cycle?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"panic: runtime error: index out of range [5] with length 5" if selecting additional columns

2 participants