{"record":{"id":"181f1305068c696b","repo":"apache/beam","slug":"schema-v-changed-got-d-fields-want-d-fields","errorCode":null,"errorMessage":"schema[%v] changed: got %d fields, want %d fields","messagePattern":"schema\\[(.+?)\\] changed: got (.+?) fields, want (.+?) fields","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/coder/row_decoder.go","lineNumber":181,"sourceCode":"\t\t\t// Add a no-op coder to fill in field index\n\t\t\tcoder.fields = append(coder.fields, typeDecoderFieldReflect{decode: func(rv reflect.Value, r io.Reader) error {\n\t\t\t\treturn nil\n\t\t\t}})\n\t\t\tcontinue\n\t\t}\n\t\tdec, err := b.decoderForSingleTypeReflect(sf.Type)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcoder.fields = append(coder.fields, dec)\n\t}\n\treturn func(rv reflect.Value, r io.Reader) error {\n\t\tnf, nils, err := ReadRowHeader(r)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif nf != len(coder.fields) {\n\t\t\treturn errors.Errorf(\"schema[%v] changed: got %d fields, want %d fields\", coder.typ, nf, len(coder.fields))\n\t\t}\n\t\tfor i, f := range coder.fields {\n\t\t\tif IsFieldNil(nils, i) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfv := rv.Field(i)\n\t\t\tif f.addr {\n\t\t\t\tfv = fv.Addr()\n\t\t\t}\n\t\t\tif err := f.decode(fv, r); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}, nil\n}\n\nfunc reflectDecodeBool(rv reflect.Value, r io.Reader) error {","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/coder/row_decoder.go#L163-L199","documentation":"Raised while decoding a schema-coded row: the row header read from the stream declares a number of fields that differs from what the decoder expects. This means the encoded data's schema no longer matches the Go struct the coder was built from — the schema changed between encode and decode.","triggerScenarios":"Calling the returned decode closure (from decoderForStructReflect) on a byte stream whose ReadRowHeader reports nf != len(coder.fields), e.g. decoding an old snapshot/output with a newer or older version of the struct, or mixing pipeline outputs with changed types.","commonSituations":"Deploying an updated binary that added/removed struct fields and then re-reading materialized data or rerunning with cached/staged input; also cross-version data exchange between jobs.","solutions":["Regenerate or re-encode the data with the current schema instead of decoding stale data.","Add the new field as exported with matching order, or keep schema evolution compatible (append fields at the end) and ensure field count expectations match.","Use schema evolution-aware storage or migrate old data with the old coder version.","Check that both pipeline stages use the same struct type/version."],"exampleFix":"// before (struct changed incompatibly)\ntype Row struct { A string }\n// reading old data written with two fields\n\n// after (compatible evolution)\ntype Row struct { A string; B string } // appended in same order as writer's schema","handlingStrategy":"fallback","validationCode":"// Before decoding persisted data, compare its header against expectations:\nnf, _, err := coder.ReadRowHeader(r)\nif err != nil { return err }\nif nf != expectedFieldCount {\n    return fmt.Errorf(\"stored schema has %d fields, code expects %d; migrate data first\", nf, expectedFieldCount)\n}","typeGuard":null,"tryCatchPattern":"row, err := decodeRow(data)\nif err != nil && strings.Contains(err.Error(), \"schema\") && strings.Contains(err.Error(), \"changed\") {\n    return migrateAndDecode(data) // decode with old coder version\n}","preventionTips":["Version your persisted row data and keep old decoders for migration.","Only append fields at the end of structs to keep evolution compatible.","Avoid reusing stored row blobs across struct refactors.","Write integration tests that decode previously stored fixtures after schema changes."],"tags":["schema-changed","field-count-mismatch","row-decoding","data-compatibility"],"backgroundTag":"schema-validation-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}