{"record":{"id":"a050b5da227edcb7","repo":"apache/beam","slug":"cannot-make-schema-decoder-for-type-v-as-it-has-unexported","errorCode":null,"errorMessage":"cannot make schema decoder for type %v as it has unexported fields such as %s.","messagePattern":"cannot make schema decoder for type (.+?) as it has unexported fields such as (.+?)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/coder/row_decoder.go","lineNumber":160,"sourceCode":"\t\t\t\t// See https://golang.org/issue/21357\n\t\t\t\t//\n\t\t\t\t// Since the values are created by this package reflectively,\n\t\t\t\t// there's no work around like pre-allocating the field\n\t\t\t\t// manually.\n\t\t\t\tif isUnexported {\n\t\t\t\t\treturn nil, errors.Errorf(\"cannot make schema decoder for type %v as it has an embedded field of a pointer to an unexported type %v. See https://golang.org/issue/21357\", t, ft.Elem())\n\t\t\t\t}\n\t\t\t\tft = ft.Elem()\n\t\t\t}\n\t\t\tif isUnexported && ft.Kind() != reflect.Struct {\n\t\t\t\t// Ignore embedded fields of unexported non-struct types.\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Do not ignore embedded fields of unexported struct types\n\t\t\t// since they may have exported fields.\n\t\t} else if isUnexported {\n\t\t\tif b.RequireAllFieldsExported {\n\t\t\t\treturn nil, errors.Errorf(\"cannot make schema decoder for type %v as it has unexported fields such as %s.\", t, sf.Name)\n\t\t\t}\n\t\t\t// Silently ignore, since we can't do anything about it.\n\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","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/coder/row_decoder.go#L142-L178","documentation":"The struct type has unexported fields and the decoder options set RequireAllFieldsExported, so the reflective schema decoder refuses to be built rather than silently dropping data. Without the flag the SDK silently adds a no-op decoder for such fields, meaning data loss; with the flag it fails fast.","triggerScenarios":"decoderForStructReflect (via decoderForType) on a struct with any lowercase/unexported field (e.g. `mu sync.Mutex` or `cached string`) while DecoderOptions.RequireAllFieldsExported is true — typically set via RowCoder construction or schema registration with strict options.","commonSituations":"Users enable RequireAllFieldsExported to avoid silent data loss, then hit it on types with mutexes, sync primitives, or cache fields; common when upgrading pipelines that previously used lenient decoding.","solutions":["Export the offending field (rename, e.g. `cached` → `Cached`) if it is meaningful data.","Remove fields that are not part of the logical row (e.g. sync.Mutex) from the encoded struct.","Disable RequireAllFieldsExported if silently ignoring unexported fields is acceptable.","Provide a custom coder for the type."],"exampleFix":"// before\ntype Record struct {\n    ID    string\n    cache string // unexported\n}\n\n// after\ntype Record struct {\n    ID    string\n    Cache string\n}","handlingStrategy":"validation","validationCode":"func requireExportedFields(t reflect.Type) error {\n    for i := 0; i < t.NumField(); i++ {\n        if !t.Field(i).IsExported() {\n            return fmt.Errorf(\"type %s has unexported field %s\", t, t.Field(i).Name)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := requireExportedFields(reflect.TypeOf(myRecord{})); err != nil {\n    return fmt.Errorf(\"record not row-encodable: %w\", err)\n}","preventionTips":["Audit structs used in schema coding for unexported fields (mutexes, caches).","Keep RequireAllFieldsExported enabled in CI tests to fail fast at compile/deploy time.","Prefer exported field names for all persisted data.","Use custom coders for types that must keep unexported internals."],"tags":["schema-decoder","unexported-field","strict-mode","row-encoding"],"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"}