{"record":{"id":"92a147fc12694fe4","repo":"apache/beam","slug":"nested-type-in-struct-v-not-permitted-in-concrete-types","errorCode":null,"errorMessage":"Nested type in struct \"%v\" not permitted in concrete types.","messagePattern":"Nested type in struct \"(.+?)\" not permitted in concrete types\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/typex/class.go","lineNumber":167,"sourceCode":"\t\tif err != nil {\n\t\t\terr = errors.Wrapf(err, \"Nested type in %v \\\"%v\\\" not permitted in concrete types.\", t.Kind(), t)\n\t\t}\n\t\treturn err\n\n\tcase reflect.Struct:\n\t\tfor i := 0; i < t.NumField(); i++ {\n\t\t\t// We ignore private fields under the assumption that they are\n\t\t\t// either not needed or will be coded manually. For combiner\n\t\t\t// accumulators, we need types that need non-trivial coding. Also,\n\t\t\t// Go serialization schemes in general ignore private fields.\n\n\t\t\tf := t.Field(i)\n\t\t\tif len(f.Name) > 0 {\n\t\t\t\tr, _ := utf8.DecodeRuneInString(f.Name)\n\t\t\t\tif unicode.IsUpper(r) {\n\t\t\t\t\terr := isConcrete(f.Type, visited)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn errors.Wrapf(err, \"Nested type in struct \\\"%v\\\" not permitted in concrete types.\", t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn nil\n\n\tcase reflect.Interface:\n\t\t// Interface types must fail at construction time if no coder is registered for them.\n\t\treturn nil\n\n\tcase reflect.Bool:\n\t\treturn nil\n\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn nil\n\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\treturn nil","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/typex/class.go#L149-L185","documentation":"When validating a struct type, isConcrete recurses into each exported (upper-case initial) field; if any field's type fails validation, the error is wrapped with 'Nested type in struct ...' naming the containing struct. Private fields are deliberately ignored, so only exported fields can trigger this.","triggerScenarios":"Using an element type struct with an exported chan, func, unsafe.Pointer, uintptr, or context/error-typed field — e.g. struct{ Data []byte; Cancel context.Context } or struct{ Err error }.","commonSituations":"Carrying context.Context or error in event records; structs that embed a mutex plus a channel for signaling; records that double as application objects with callback hooks.","solutions":["Remove or unexport the offending field (unexported fields are skipped by validation).","Keep context and errors out of element types: handle errors via side outputs, metrics, or logging inside DoFns.","Split transport-safe records from runtime-only state in separate types.","Call typex.CheckConcrete(reflect.TypeOf(record)) in tests to catch offending fields early."],"exampleFix":"// before\ntype Record struct {\n    Payload []byte\n    Ctx     context.Context\n}\n\n// after\ntype Record struct {\n    Payload []byte\n}","handlingStrategy":"validation","validationCode":"if err := typex.CheckConcrete(reflect.TypeOf(record)); err != nil {\n    return fmt.Errorf(\"struct element type rejected: %w\", err)\n}","typeGuard":"func structFieldsSafe(t reflect.Type) bool {\n    if t.Kind() != reflect.Struct {\n        return true\n    }\n    for i := 0; i < t.NumField(); i++ {\n        if t.Field(i).PkgPath != \"\" {\n            continue // unexported\n        }\n        switch t.Field(i).Type.Kind() {\n        case reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Uintptr:\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":null,"preventionTips":["Keep context.Context and error out of exported record fields.","Unexport runtime-only fields (mutexes, channels, callbacks) so validation skips them.","Separate transport-safe records from application objects with hooks."],"tags":["go","apache-beam","type-system","serialization"],"backgroundTag":"type-mismatch","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"}