apache/beam · error
Nested type in struct
Error message
Nested type in struct "%v" not permitted in concrete types.
What it means
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.
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.
Example fix
// before
type Record struct {
Payload []byte
Ctx context.Context
}
// after
type Record struct {
Payload []byte
} Defensive patterns
Strategy: validation
Validate before calling
if err := typex.CheckConcrete(reflect.TypeOf(record)); err != nil {
return fmt.Errorf("struct element type rejected: %w", err)
} Type guard
func structFieldsSafe(t reflect.Type) bool {
if t.Kind() != reflect.Struct {
return true
}
for i := 0; i < t.NumField(); i++ {
if t.Field(i).PkgPath != "" {
continue // unexported
}
switch t.Field(i).Type.Kind() {
case reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Uintptr:
return false
}
}
return true
} Prevention
- 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.
When it happens
Trigger: 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 }.
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Type " " of kind " " not permitted in concrete types. All…
- Type " " of kind " " not permitted in concrete types. All…
- bad base type
- bad channel direction
- bad element type
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/92a147fc12694fe4.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/typex/class.go:167
if err != nil {
err = errors.Wrapf(err, "Nested type in %v \"%v\" not permitted in concrete types.", t.Kind(), t)
}
return err
case reflect.Struct:
for i := 0; i < t.NumField(); i++ {
// We ignore private fields under the assumption that they are
// either not needed or will be coded manually. For combiner
// accumulators, we need types that need non-trivial coding. Also,
// Go serialization schemes in general ignore private fields.
f := t.Field(i)
if len(f.Name) > 0 {
r, _ := utf8.DecodeRuneInString(f.Name)
if unicode.IsUpper(r) {
err := isConcrete(f.Type, visited)
if err != nil {
return errors.Wrapf(err, "Nested type in struct \"%v\" not permitted in concrete types.", t)
}
}
}
}
return nil
case reflect.Interface:
// Interface types must fail at construction time if no coder is registered for them.
return nil
case reflect.Bool:
return nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return nilView on GitHub (pinned to 12126d8942)