wavetermdev/waveterm · error
Component function must return exactly 1 value
Error message
Component function must return exactly 1 value
What it means
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".
Source
Thrown at tsunami/engine/rootelem.go:249
defer r.atomLock.Unlock()
delete(r.Atoms, name)
}
func validateCFunc(cfunc any) error {
if cfunc == nil {
return fmt.Errorf("Component function cannot b nil")
}
rval := reflect.ValueOf(cfunc)
if rval.Kind() != reflect.Func {
return fmt.Errorf("Component function must be a function")
}
rtype := rval.Type()
if rtype.NumIn() != 1 {
return fmt.Errorf("Component function must take exactly 1 argument")
}
if rtype.NumOut() != 1 {
return fmt.Errorf("Component function must return exactly 1 value")
}
// first argument can be a map[string]any, or a struct, or ptr to struct (we'll reflect the value into it)
arg1Type := rtype.In(0)
if arg1Type.Kind() == reflect.Ptr {
arg1Type = arg1Type.Elem()
}
if arg1Type.Kind() == reflect.Map {
if arg1Type.Key().Kind() != reflect.String ||
!(arg1Type.Elem().Kind() == reflect.Interface && arg1Type.Elem().NumMethod() == 0) {
return fmt.Errorf("Map argument must be map[string]any")
}
} else if arg1Type.Kind() != reflect.Struct &&
!(arg1Type.Kind() == reflect.Interface && arg1Type.NumMethod() == 0) {
return fmt.Errorf("Component function argument must be map[string]any, struct, or any")
}
return nil
}
View on GitHub (pinned to a4447c1563)
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
Example fix
// before
root.RegisterComponent("stats", func(p map[string]any) (any, error) { ... })
// after
root.RegisterComponent("stats", func(p map[string]any) any {
v, err := computeStats(p)
if err != nil { return errorView(err) }
return v
}) Defensive patterns
Strategy: validation
Validate before calling
t := reflect.TypeOf(cfunc)
if t != nil && t.Kind() == reflect.Func && t.NumOut() != 1 {
return fmt.Errorf("need exactly 1 return value, got %d", t.NumOut())
} Type guard
func isSingleReturnFunc(v any) bool {
t := reflect.TypeOf(v)
return t != nil && t.Kind() == reflect.Func && t.NumIn() == 1 && t.NumOut() == 1
} Try / catch
if err := root.RegisterComponent(name, fn); err != nil {
return fmt.Errorf("component %s must return exactly 1 value: %w", name, err)
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Component function must take exactly 1 argument
- Map argument must be map[string]any
- Component function argument must be map[string]any, struct,
- invalid number type %s
- invalid argument type %s
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/074b504e35acd13a.
Report an issue: GitHub.