{"record":{"id":"074b504e35acd13a","repo":"wavetermdev/waveterm","slug":"component-function-must-return-exactly-1-value-074b50","errorCode":null,"errorMessage":"Component function must return exactly 1 value","messagePattern":"Component function must return exactly 1 value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tsunami/engine/rootelem.go","lineNumber":249,"sourceCode":"\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}\n\treturn nil\n}\n","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/engine/rootelem.go#L231-L267","documentation":"The engine treats the single return value of a component function as the rendered component output, so validateCFunc requires rtype.NumOut() == 1. Functions returning zero values or multiple values (e.g. (any, error)) are rejected with \"Component function must return exactly 1 value\".","triggerScenarios":"RegisterComponent with func(map[string]any) (any, error); registering a function that returns nothing (func(map[string]any) {}); registering a helper whose idiomatic Go signature is (T, error).","commonSituations":"Returning (result, error) out of Go habit; registering an existing function with a multi-value signature instead of wrapping it; registering a void procedure instead of a render function.","solutions":["Make the function return exactly one value (the component output)","If errors are possible, handle them inside the function and return an error component/value instead","Wrap multi-return helpers in a single-return closure"],"exampleFix":"// before\nroot.RegisterComponent(\"stats\", func(p map[string]any) (any, error) { ... })\n// after\nroot.RegisterComponent(\"stats\", func(p map[string]any) any {\n    v, err := computeStats(p)\n    if err != nil { return errorView(err) }\n    return v\n})","handlingStrategy":"validation","validationCode":"t := reflect.TypeOf(cfunc)\nif t != nil && t.Kind() == reflect.Func && t.NumOut() != 1 {\n    return fmt.Errorf(\"need exactly 1 return value, got %d\", t.NumOut())\n}","typeGuard":"func isSingleReturnFunc(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 must return exactly 1 value: %w\", name, err)\n}","preventionTips":["Return the component output as the single value; handle errors inside the function and return an error view","Never register (T, error) or void functions directly — wrap them in a closure","Declare handlers with an explicit named type like type CompFunc func(map[string]any) any"],"tags":["go","reflection","signature","return-value"],"backgroundTag":"callback-signature-mismatch","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}