{"record":{"id":"d2c349bb77daf560","repo":"wavetermdev/waveterm","slug":"component-function-must-take-exactly-1-argument","errorCode":null,"errorMessage":"Component function must take exactly 1 argument","messagePattern":"Component function must take exactly 1 argument","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tsunami/engine/rootelem.go","lineNumber":246,"sourceCode":"\nfunc (r *RootElem) RemoveAtom(name string) {\n\tr.atomLock.Lock()\n\tdefer r.atomLock.Unlock()\n\n\tdelete(r.Atoms, name)\n}\n\nfunc validateCFunc(cfunc any) error {\n\tif cfunc == nil {\n\t\treturn fmt.Errorf(\"Component function cannot b nil\")\n\t}\n\trval := reflect.ValueOf(cfunc)\n\tif rval.Kind() != reflect.Func {\n\t\treturn fmt.Errorf(\"Component function must be a function\")\n\t}\n\trtype := rval.Type()\n\tif rtype.NumIn() != 1 {\n\t\treturn fmt.Errorf(\"Component function must take exactly 1 argument\")\n\t}\n\tif rtype.NumOut() != 1 {\n\t\treturn fmt.Errorf(\"Component function must return exactly 1 value\")\n\t}\n\t// first argument can be a map[string]any, or a struct, or ptr to struct (we'll reflect the value into it)\n\targ1Type := rtype.In(0)\n\tif arg1Type.Kind() == reflect.Ptr {\n\t\targ1Type = arg1Type.Elem()\n\t}\n\tif arg1Type.Kind() == reflect.Map {\n\t\tif arg1Type.Key().Kind() != reflect.String ||\n\t\t\t!(arg1Type.Elem().Kind() == reflect.Interface && arg1Type.Elem().NumMethod() == 0) {\n\t\t\treturn fmt.Errorf(\"Map argument must be map[string]any\")\n\t\t}\n\t} else if arg1Type.Kind() != reflect.Struct &&\n\t\t!(arg1Type.Kind() == reflect.Interface && arg1Type.NumMethod() == 0) {\n\t\treturn fmt.Errorf(\"Component function argument must be map[string]any, struct, or any\")\n\t}","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/engine/rootelem.go#L228-L264","documentation":"Component functions are invoked by the engine with exactly one argument (the props/data from the frontend), so validateCFunc requires rtype.NumIn() == 1. Functions with zero arguments or two or more arguments are rejected with \"Component function must take exactly 1 argument\".","triggerScenarios":"RegisterComponent with func() any (0 args); RegisterComponent with func(ctx context.Context, props map[string]any) any (2 args); binding a standard handler that takes (w, r) style pairs.","commonSituations":"Reusing an ordinary helper function as a component function; adapting a generic event handler signature; adding a context parameter during refactoring without matching the library's single-argument convention.","solutions":["Change the function to accept exactly one argument: the props as map[string]any, a struct, *struct, or any","If extra parameters are needed, close over them in a closure that takes a single argument","Split multi-argument logic into a helper and register a single-arg wrapper"],"exampleFix":"// before\nroot.RegisterComponent(\"clock\", func(tz string, fmtStr string) any { ... })\n// after\ntz, fmtStr := \"UTC\", time.Kitchen\nroot.RegisterComponent(\"clock\", func(props map[string]any) any {\n    return renderClock(tz, fmtStr) // capture extras via closure\n})","handlingStrategy":"validation","validationCode":"t := reflect.TypeOf(cfunc)\nif t != nil && t.Kind() == reflect.Func && t.NumIn() != 1 {\n    return fmt.Errorf(\"need exactly 1 arg, got %d\", t.NumIn())\n}","typeGuard":"func isSingleArgFunc(v any) bool {\n    t := reflect.TypeOf(v)\n    return t != nil && t.Kind() == reflect.Func && t.NumIn() == 1 && t.NumOut() == 1\n}","tryCatchPattern":"if err := root.RegisterComponent(name, fn); err != nil {\n    return fmt.Errorf(\"component %s signature invalid: %w\", name, err)\n}","preventionTips":["Follow the canonical signature func(map[string]any) any (or struct/*struct/any param)","Capture extra dependencies in closures instead of adding parameters","Check signatures with the compiler by declaring the func as a named type before registering"],"tags":["go","reflection","signature","registration"],"backgroundTag":"callback-signature-mismatch","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}