{"record":{"id":"536bbbd98bb8d130","repo":"apache/beam","slug":"not-a-function-v","errorCode":null,"errorMessage":"not a function: %v","messagePattern":"not a function: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/funcx/signature.go","lineNumber":122,"sourceCode":"//\n//\tfoo : (context.Context, X) -> bool\n//\tbar : (int) -> bool\n//\n// both would satisfy a signature of (context.Context?, int) -> bool. Only\n// \"foo\" would satisfy (context.Context, string) -> bool and only \"bar\" would\n// satisfy (int) -> bool.\nfunc Satisfy(fn any, sig *Signature) error {\n\tvar in, out []reflect.Type\n\tvar typ reflect.Type\n\tswitch fx := fn.(type) {\n\tcase *Fn:\n\t\ttyp = fx.Fn.Type()\n\tcase reflectx.Func:\n\t\ttyp = fx.Type()\n\tdefault:\n\t\tvalue := reflect.ValueOf(fn)\n\t\tif value.Kind() != reflect.Func {\n\t\t\treturn errors.Errorf(\"not a function: %v\", value)\n\t\t}\n\t\ttyp = value.Type()\n\t}\n\tfor i := 0; i < typ.NumIn(); i++ {\n\t\tin = append(in, typ.In(i))\n\t}\n\tfor i := 0; i < typ.NumOut(); i++ {\n\t\tout = append(out, typ.Out(i))\n\t}\n\tif len(in) < len(sig.Args) || len(out) < len(sig.Return) {\n\t\treturn errors.Errorf(\"not enough required parameters: %v\", typ)\n\t}\n\n\tif len(in) > len(sig.Args)+len(sig.OptArgs) || len(out) > len(sig.Return)+len(sig.OptReturn) {\n\t\treturn errors.Errorf(\"too many parameters: %v\", typ)\n\t}\n\n\t// (1) Create generic binding. If inconsistent, reject fn. We do not allow","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/funcx/signature.go#L104-L140","documentation":"Satisfy in sdks/go/pkg/beam/core/funcx/signature.go validates that a value satisfies the funcx function contract. When the argument is neither a *funcx.Fn nor a reflect Func kind, it reflects on the value and, if value.Kind() != reflect.Func, returns \"not a function: %v\". The library throws it because signature analysis (NumIn/NumOut/parameter types) is only possible on actual function values.","triggerScenarios":"Calling fx.Satisfy / fx.MustSatisfy / validateEncoder-style helpers with a non-function value such as a struct, method value bound incorrectly, nil, a funcx.Fn-typed wrapper used in the wrong branch, or a variable that was expected to hold a function but holds its result (e.g. `fn := myFunc()` instead of `fn := myFunc`).","commonSituations":"Passing a closure's invocation result instead of the closure itself; passing a method call `obj.Method` written as `obj.Method()`; handing a nil interface to MustSatisfy in an init path; type confusion after refactoring a helper that returned a function.","solutions":["Pass an actual function value: `fx.Satisfy(myFunc)` not `fx.Satisfy(myFunc())`.","If you have a *funcx.Fn, pass it directly — it is accepted via the fx.Fn branch.","Check for nil or shadowed variables holding the wrong value before calling Satisfy.","Wrap with fx.MustSatisfy only in tests/init; prefer fx.Satisfy and handle the returned error in production paths."],"exampleFix":"// before\nfn := buildFn() // returns bool, not a func\nfx.MustSatisfy(fn)\n// after\nfn := buildFn   // the function value itself\nfx.MustSatisfy(fn)","handlingStrategy":"type-guard","validationCode":"func requireFunc(v interface{}) error {\n\tif v == nil {\n\t\treturn errors.New(\"fn is nil\")\n\t}\n\tif _, ok := v.(*fx.Fn); ok {\n\t\treturn nil\n\t}\n\tif reflect.TypeOf(v).Kind() != reflect.Func {\n\t\treturn fmt.Errorf(\"%T is not a function\", v)\n\t}\n\treturn nil\n}","typeGuard":"func isFuncValue(v interface{}) bool {\n\tif v == nil {\n\t\treturn false\n\t}\n\tif _, ok := v.(*fx.Fn); ok {\n\t\treturn true\n\t}\n\treturn reflect.TypeOf(v).Kind() == reflect.Func\n}","tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\t// MustSatisfy may panic on non-functions\n\t\terr = fmt.Errorf(\"signature check failed: %v\", r)\n\t}\n}()\n// or avoid panic entirely:\nif err := fx.Satisfy(fn); err != nil {\n\treturn fmt.Errorf(\"not a function: %w\", err)\n}","preventionTips":["Never call a function when you mean to pass it: drop the `()`.","Check for nil before passing function-typed variables.","Prefer fx.Satisfy (returns error) over fx.MustSatisfy outside tests and init.","When a helper returns a callback, verify its return type is the func, not the result."],"tags":["go","beam","funcx","function-signature","reflection"],"backgroundTag":"type-mismatch","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"}