Skip to content

fix(finisher_api): resolve FindInBatches cursor primary key from dest schema - #7820

Open
wbrunovieira wants to merge 1 commit into
go-gorm:masterfrom
wbrunovieira:fix/7737-findinbatches-model-dest-mismatch
Open

fix(finisher_api): resolve FindInBatches cursor primary key from dest schema#7820
wbrunovieira wants to merge 1 commit into
go-gorm:masterfrom
wbrunovieira:fix/7737-findinbatches-model-dest-mismatch

Conversation

@wbrunovieira

Copy link
Copy Markdown

What this fixes

Model(A).FindInBatches(&[]B{}, ...) — where B embeds A but has a different field layout — panics with reflect: Field index out of range (v1.31.1) or, on current master, returns sql: converting argument $2 type: unsupported type gorm.Model, a struct and breaks pagination.

Reproduction: #7737 (playground: go-gorm/playground#848).

Root cause

The batch cursor reads the primary key of the last scanned row via result.Statement.Schema.PrioritizedPrimaryField.ValueOf(...). When a Model is set, Statement.Schema is the Model's schema, whose field Index path does not apply to the destination's element type — so the read resolves the wrong field (a whole embedded struct, or an out-of-range index).

The scan path already handles this by re-parsing the schema from dest when the element type differs from the Model type (scan.go:212-214). FindInBatches was the one place still reading the cursor value through the Model schema.

Fix

Resolve the cursor's primary field from the destination's own schema, matched by the Model's primary-key column name (LookUpField(DBName)), so the value always corresponds to the same column used in the ORDER BY / > comparison (which is built from the Model schema). The common case (dest type == Model type) keeps the Model's field unchanged. If dest has no field for that column there is no valid cursor, so it fails with ErrPrimaryKeyRequired instead of risking a wrong-index read.

Tests

TestFindInBatchesModelDestMismatch (in tests/) covers []B and []*B destinations and asserts every row is paged exactly once (no duplicate, no skip) across batches with batchSize < total. It fails without the fix (the exact #7737 error) and passes with it.

Closes #7737

… schema

FindInBatches builds its batch cursor by reading the primary key of the last
scanned row through Statement.Schema. When a different Model is set (e.g.
Model(A).FindInBatches(&[]B{})), Statement.Schema describes A, whose field index
does not apply to B, so the read returns the wrong field (panic "reflect: Field
index out of range" on older versions, "sql: unsupported type ..." on master),
breaking pagination.

Resolve the primary field from dest's own schema, matched by the Model's
primary-key column name so the cursor value stays in sync with the ORDER BY /
comparison column. Mirrors how Scan already re-parses a mismatched dest. When
dest has no field for that column, fail with ErrPrimaryKeyRequired.

Adds a regression test covering []B and []*B destinations.

Closes go-gorm#7737
@wbrunovieira
wbrunovieira force-pushed the fix/7737-findinbatches-model-dest-mismatch branch from 40f63d0 to b6be0cb Compare July 6, 2026 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Model(A).FindInBatches(B) cause panic: reflect: Field index out of range

1 participant