{"record":{"id":"b78ca9e4d9368ca8","repo":"apache/beam","slug":"invalid-signature-for-uppername","errorCode":null,"errorMessage":"Invalid signature for {{$upperName}}","messagePattern":"Invalid signature for (.+?)\\}","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"sdks/go/pkg/beam/register/register.tmpl","lineNumber":37,"sourceCode":"\t{{$lowerName}}Out := -1\n\t{{$lowerName}}Method := reflect.ValueOf(doFn).MethodByName(\"{{$upperName}}\")\n\tif !{{$lowerName}}Method.IsValid() {\n        return nil\n    }\n    {{$lowerName}}In = {{$lowerName}}Method.Type().NumIn()\n    {{$lowerName}}Out = {{$lowerName}}Method.Type().NumOut()\n    switch {\n    {{range $funcIn := upto $startFinishBundleMaxIn}}\n    case {{$lowerName}}In == {{$funcIn}}:\n            switch { {{range $funcOut := upto 2}}{{$possibleCombos := (possibleBundleLifecycleParameterCombos $funcIn $numParams)}}{{if $possibleCombos}}\n            case {{$lowerName}}Out == {{$funcOut}}:\n    {{$first := true}}{{range $funcCombo := $possibleCombos}}{{if $first}}{{$first = false}}                {{else}} else {{end}}if _, ok := doFn.({{$lowerName}}{{$funcIn}}x{{$funcOut}}{{if (or $funcIn $funcOut)}}[{{(join $funcCombo \", \")}}{{if $funcOut}}{{if $funcIn}}, {{end}}error{{end}}]{{end}}); ok {\n                    return register{{$upperName}}{{$funcIn}}x{{$funcOut}}FuncAndMakeStructWrapper{{if (or $funcIn $funcOut)}}[{{(join $funcCombo \", \")}}{{if $funcOut}}{{if $funcIn}}, {{end}}error{{end}}]{{end}}()\n                } {{end}}{{end}}else {\n                    panic(\"Unable to infer the types of {{$upperName}}\")\n                }{{end}}\n            default:\n                panic(\"Invalid signature for {{$upperName}}\")\n            }\n    {{end}}\n    default:\n        panic(\"Invalid signature for {{$upperName}}\")\n    }\n}\n{{end}}{{define \"BuildWrapper_SetupTeardown\"}}\n{{$lowerName := \"unknown\"}}{{$upperName := \"unknown\"}}{{if (eq .func \"setup\")}}{{$lowerName = \"setup\"}}{{$upperName = \"Setup\"}}{{end}}{{if (eq .func \"teardown\")}}{{$lowerName = \"teardown\"}}{{$upperName = \"Teardown\"}}{{end}}\nfunc build{{$upperName}}Wrapper(doFn any) func(any) reflectx.Func {\n    if _, ok := doFn.({{$lowerName}}0x0); ok {\n        {{$lowerName}}Caller := func(fn any) reflectx.Func {\n            f := fn.(func())\n            return &caller0x0{fn: f}\n        }\n        reflectx.RegisterFunc(reflect.TypeOf((*func())(nil)).Elem(), {{$lowerName}}Caller)\n\n        return func(fn any) reflectx.Func {\n            return reflectx.MakeFunc(func() {","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/register/register.tmpl#L19-L55","documentation":"This panic is raised by the generated buildStartBundleWrapper/buildFinishBundleWrapper functions in Apache Beam Go's register package (rendered from register.tmpl). The DoFn has a StartBundle or FinishBundle method (found via reflect.MethodByName), but its signature's number of outputs (or number of inputs) doesn't fall into any supported case in the generated switch — only 0 or 1 outputs and up to startFinishBundleMaxIn inputs are supported. The library panics because it cannot build a wrapper for an unsupported method shape.","triggerScenarios":"Registering a DoFn whose StartBundle/FinishBundle method returns 2+ values (e.g. func(context.Context) (T0, T1, error)), or takes more inputs than the configured maximum (startFinishBundleMaxIn, driven by ProcessElement max params); also the outer default case when NumIn exceeds all enumerated cases.","commonSituations":"Porting DoFns from other Beam SDKs that allow richer lifecycle signatures; adding extra return values like (bool, error) for control flow; auto-generated DoFn wrappers with bloated signatures; newer Beam versions raising/lowering the supported arity so previously-working code panics after upgrade.","solutions":["Change StartBundle/FinishBundle to return at most one value (either nothing or error): e.g. func (fn *MyFn) FinishBundle() error.","Reduce lifecycle method parameters to the supported set (none, or context.Context and/or the accumulator types matching ProcessElement combos).","Move extra logic/returns out of the lifecycle method into ProcessElement or struct state.","Check the Beam version's supported signature table in sdks/go/pkg/beam/core/graph/coder or register docs and conform to it.","If a method genuinely isn't a lifecycle hook, rename it so reflect.MethodByName doesn't pick it up."],"exampleFix":"// before: two outputs unsupported\ntype MyFn struct{}\nfunc (fn *MyFn) StartBundle(ctx context.Context) (bool, error) { return true, nil }\n\n// after: at most one output\ntype MyFn struct{}\nfunc (fn *MyFn) StartBundle(ctx context.Context) error { return nil }","handlingStrategy":"validation","validationCode":"// Pre-check outputs/inputs of lifecycle methods before registration:\nfunc checkSig(fn any, method string, maxIn int) error {\n    m := reflect.ValueOf(fn).MethodByName(method)\n    if !m.IsValid() {\n        return nil\n    }\n    t := m.Type()\n    if t.NumIn() > maxIn {\n        return fmt.Errorf(\"%s: %d inputs exceeds max %d\", method, t.NumIn(), maxIn)\n    }\n    if t.NumOut() > 1 {\n        return fmt.Errorf(\"%s: %d outputs exceeds max 1\", method, t.NumOut())\n    }\n    return nil\n}","typeGuard":"func hasSupportedFinishBundle(fn any) bool {\n    _, ok := fn.(interface{ FinishBundle() })\n    _, okE := fn.(interface{ FinishBundle() error })\n    return ok || okE\n}","tryCatchPattern":"func registerSafe(fn any) {\n    defer func() {\n        if r := recover(); r != nil {\n            log.Fatalf(\"unsupported DoFn signature (fix StartBundle/FinishBundle/Setup/Teardown shape): %v\", r)\n        }\n    }()\n    register.DoFn2x1(fn)\n}","preventionTips":["Never return more than one value (or one error) from lifecycle methods.","Keep lifecycle inputs to the documented set: none, context.Context, and/or accumulator types.","Add CI tests that call the registration path for all DoFns to catch signature regressions.","After upgrading Beam, re-run registration tests since supported arities are template-configured."],"tags":["go","apache-beam","panics","function-signature","reflection"],"backgroundTag":"invalid-argument-format","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}