{"record":{"id":"888f756211c60489","repo":"apache/beam","slug":"panic-err-external","errorCode":null,"errorMessage":"panic(err)","messagePattern":"panic\\(err\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/transforms/xlang/schema/external.go","lineNumber":76,"sourceCode":"// UnnamedOutputType specifies an output PCollection type of the transform.\n// It must match the external transform's output schema.  This is simply\n// syntactic sugar for OutputType(beam.UnnamedOutputTag(), tpe).\nfunc UnnamedOutputType(tpe beam.FullType) Option {\n\treturn OutputType(beam.UnnamedOutputTag(), tpe)\n}\n\n// ExpansionAddr is the URL of the expansion service to use.\nfunc ExpansionAddr(addr string) Option {\n\treturn func(opts *options) {\n\t\topts.expansionAddr = addr\n\t}\n}\n\n// Transform configures a new cross language transform to call a \"schema transform\" in an external SDK.\nfunc Transform(scope beam.Scope, config any, transformIdentifier string, opts ...Option) map[string]beam.PCollection {\n\tecp, err := xlangx.CreateExternalConfigurationPayload(config)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tpl, err := proto.Marshal(&pipepb.SchemaTransformPayload{\n\t\tIdentifier:          transformIdentifier,\n\t\tConfigurationSchema: ecp.GetSchema(),\n\t\tConfigurationRow:    ecp.GetPayload(),\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tallOpts := &options{}\n\tfor _, o := range opts {\n\t\to(allOpts)\n\t}\n\n\treturn beam.CrossLanguage(scope, schemaTransformURN, pl, allOpts.expansionAddr, allOpts.inputs, allOpts.outputTypes)\n}","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/transforms/xlang/schema/external.go#L58-L94","documentation":"schema.Transform builds a cross-language schema-transform call. It first converts the Go config value into an external configuration payload via xlangx.CreateExternalConfigurationPayload; if that conversion (reflection over the config struct into a schema + Row) fails, the panic propagates. Marshal errors for the SchemaTransformPayload also panic. It means your config value could not be represented as an external schema payload.","triggerScenarios":"Passing a config value that CreateExternalConfigurationPayload cannot encode (unsupported field types, unexported fields with no schema mapping, nil/incompatible config) to schema.Transform(scope, config, identifier, opts...).","commonSituations":"Hand-written config structs with unsupported types (maps with non-string keys, channels, funcs); passing nil config where a struct is required; refactoring an external transform's config struct so it no longer matches the external SDK's expected schema.","solutions":["Ensure the config is a plain struct with exported fields of schema-supported types (primitives, strings, bytes, nested structs, lists, maps with comparable keys).","Check for nil config; pass a zero-value struct instead of nil when no options are needed.","Compare your struct against the external transform's documented schema and add beam.RegisterSchemaProvider/type conversions for custom types.","Wrap construction in a helper that validates config fields before calling schema.Transform so failures surface early."],"exampleFix":"// before\ncfg := map[MyKey]string{...} // non-string map key: unsupported\nschema.Transform(s, cfg, \"beam:schemas:transform:v1\")\n\n// after\ntype Cfg struct {\n    Name string `beam:\"name\"`\n}\nschema.Transform(s, Cfg{Name: \"x\"}, \"beam:schemas:transform:v1\")","handlingStrategy":"validation","validationCode":"func validateXlangConfig(cfg any) error {\n    if cfg == nil {\n        return errors.New(\"schema.Transform: config must not be nil\")\n    }\n    rv := reflect.ValueOf(cfg)\n    for rv.Kind() == reflect.Ptr {\n        rv = rv.Elem()\n    }\n    if rv.Kind() != reflect.Struct {\n        return fmt.Errorf(\"config must be a struct, got %T\", cfg)\n    }\n    rt := rv.Type()\n    for i := 0; i < rt.NumField(); i++ {\n        if rt.Field(i).PkgPath != \"\" {\n            return fmt.Errorf(\"field %s is unexported\", rt.Field(i).Name)\n        }\n    }\n    return nil\n}","typeGuard":"func isSchemaFriendly(cfg any) bool {\n    if cfg == nil {\n        return false\n    }\n    rv := reflect.ValueOf(cfg)\n    for rv.Kind() == reflect.Ptr {\n        rv = rv.Elem()\n    }\n    return rv.Kind() == reflect.Struct\n}","tryCatchPattern":"func(cfg any, id string) (map[string]beam.PCollection, error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"xlang transform %s config rejected: %v\", id, r)\n        }\n    }()\n    out := schema.Transform(scope, cfg, id, opts...)\n    return out, nil\n}","preventionTips":["Use plain structs with exported, schema-supported fields for external transform configs.","Keep the Go config struct in sync with the external SDK transform's schema.","Validate configs in a unit test that builds the transform against a local scope.","Never pass nil; pass a zero-value struct when there are no options."],"tags":["go","apache-beam","panic","xlang","schema-transform"],"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"}