apache/beam · error

non struct type received in structToSchema

Error message

non struct type received in structToSchema: %v is kind %v

What it means

Registry.structToSchema asserts its input is a struct kind; any other kind reaching it is an internal misuse. This is an invariant error — its callers (fromType, reflectTypeToFieldType) are supposed to pre-filter, so a non-struct here indicates a logic bug or unexpected registry state rather than unvalidated user input.

Solutions

  1. Verify with reflectx.SkipPtr(t).Kind() what kind actually arrives; debug the caller passing it.
  2. Use the public FromType API (which validates kind) rather than internal helpers.
  3. Check for local modifications to schema.go that bypass kind dispatch.
  4. File a Beam bug with the offending type if hit through unmodified public APIs.

Example fix

// before
schm, err := reg.structToSchema(reflect.TypeOf(42)) // internal misuse
// after
if reflectx.SkipPtr(t).Kind() != reflect.Struct { return nil, fmt.Errorf("not a struct: %v", t) }
schm, err := reg.FromType(t) // public path validates
Defensive patterns

Strategy: type-guard

Validate before calling

if reflectx.SkipPtr(t).Kind() != reflect.Struct {
    return fmt.Errorf("structToSchema requires struct, got %v", reflectx.SkipPtr(t).Kind())
}

Type guard

func isStructKind(t reflect.Type) bool { return reflectx.SkipPtr(t).Kind() == reflect.Struct }

Try / catch

schm, err := reg.FromType(t)
if err != nil && strings.Contains(err.Error(), "non struct type received") {
    return nil, fmt.Errorf("internal bug: non-struct reached structToSchema: %v", t)
}

Prevention

When it happens

Trigger: An internal call path (fromType on a non-cached, non-logical type, or reflectTypeToFieldType on a field) passes a non-struct reflect.Type into structToSchema — e.g. pointer handling skipped incorrectly or a map/array kind leaking through the dispatch switch.

Common situations: Local forks/patches to the schema package; surprising kinds from type aliases after skipping pointers; registry state where a field type bypasses the normal kind switch in reflectTypeToFieldType.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/dfa38a7d00e0950c. Report an issue: GitHub.

Appendix: source

Thrown at sdks/go/pkg/beam/core/runtime/graphx/schema/schema.go:503

			},
		},
	}
}

// fromLogicalOption returns the logical type id of this top
// level type if this schema has a logical equivalent.
func fromLogicalOption(opts []*pipepb.Option) (string, bool) {
	o := checkOptions(opts, optGoLogicalUrn)
	if o == nil {
		return "", false
	}
	lID := o.GetValue().GetAtomicValue().GetString_()
	return lID, true
}

func (r *Registry) structToSchema(t reflect.Type) (*pipepb.Schema, error) {
	if t.Kind() != reflect.Struct {
		return nil, errors.Errorf("non struct type received in structToSchema: %v is kind %v", t, t.Kind())
	}
	if schm, ok := r.typeToSchema[t]; ok {
		return schm, nil
	}

	ftype, lID, err := r.logicalTypeToFieldType(t)
	if err != nil {
		return nil, err
	}
	if ftype != nil {
		schm := ftype.GetRowType().GetSchema()
		schm = proto.Clone(schm).(*pipepb.Schema)
		schm.Options = append(schm.Options, logicalOption(lID))
		schm.Id = getUUID(t)
		r.typeToSchema[t] = schm
		r.idToType[schm.GetId()] = t
		return schm, nil
	}

View on GitHub (pinned to 12126d8942)