{"record":{"id":"e95615c2ae4e103d","repo":"apache/beam","slug":"cannot-make-schema-decoder-for-type-v-as-it-has-an-embedded","errorCode":null,"errorMessage":"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","messagePattern":"cannot make schema decoder for type (.+?) as it has an embedded field of a pointer to an unexported type (.+?)\\. See https://golang\\.org/issue/21357","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/coder/row_decoder.go","lineNumber":148,"sourceCode":"\tcoder.typ = t\n\tfor i := 0; i < t.NumField(); i++ {\n\t\ti := i // avoid alias issues in the closures.\n\t\tsf := t.Field(i)\n\t\tisUnexported := sf.PkgPath != \"\"\n\t\tif sf.Anonymous {\n\t\t\tft := sf.Type\n\t\t\tif ft.Kind() == reflect.Ptr {\n\t\t\t\t// If a struct embeds a pointer to an unexported type,\n\t\t\t\t// it is not possible to set a newly allocated value\n\t\t\t\t// since the field is unexported.\n\t\t\t\t//\n\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}})","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/coder/row_decoder.go#L130-L166","documentation":"The Beam Go SDK cannot build a schema row decoder for a struct type because one of its fields is embedded (anonymous) and is a pointer to an unexported type. Reflectively creating instances of such types panics in Go (golang.org/issue/21357), so the SDK refuses up-front instead of failing at decode time. Since values are created via reflection in this package, there is no workaround like pre-allocating the field.","triggerScenarios":"Calling decoderForType / decoderForSingleTypeReflect (e.g. via beam schema registration or RowCoder creation) on a struct with a field declared like `*unexportedType` as an embedded pointer field.","commonSituations":"Users register custom Go structs with beam.RegisterSchemaType (or use them in PCollection row encoding) where a struct embeds a pointer to a package-private type, often generated code or a mutex-like helper type.","solutions":["Change the embedded field to an exported type (or non-pointer embedded struct with exported fields).","Remove the embedded pointer field and hold it as a named, non-encoded field outside the schema type, or use a wrapper struct for encoding.","If the embedded unexported type is a struct and not needed, embed its exported base type instead.","Wrap the type with a custom coder (beam.CustomCoder) so reflective schema decoding is never used."],"exampleFix":"// before\ntype Outer struct {\n    *innerConfig // pointer to unexported type\n    Name string\n}\n\n// after\ntype InnerConfig struct{ Opt string }\ntype Outer struct {\n    InnerConfig\n    Name string\n}","handlingStrategy":"validation","validationCode":"func validateSchemaEncodable(t reflect.Type) error {\n    for i := 0; i < t.NumField(); i++ {\n        f := t.Field(i)\n        if f.Anonymous && f.Type.Kind() == reflect.Ptr {\n            if isUnexportedType(f.Type.Elem()) {\n                return fmt.Errorf(\"type %s embeds pointer to unexported type %s\", t, f.Type.Elem())\n            }\n        }\n    }\n    return nil\n}\nfunc isUnexportedType(t reflect.Type) bool { return !ast.IsExported(t.Name()) }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only embed exported types (or non-pointer exported structs) in schema-coded structs.","Keep mutexes, sync primitives and caches out of encoded structs.","Register a custom coder for types with unexported parts.","Run a test that builds the RowCoder for every schema type at startup."],"tags":["schema-decoder","unexported-embedded-field","reflection","row-encoding"],"backgroundTag":"unsupported-operation","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"}