wavetermdev/waveterm · error
Component function must take exactly 1 argument
Error message
Component function must take exactly 1 argument
What it means
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".
Source
Thrown at tsunami/engine/rootelem.go:246
func (r *RootElem) RemoveAtom(name string) {
r.atomLock.Lock()
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")
}View on GitHub (pinned to a4447c1563)
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
Example fix
// before
root.RegisterComponent("clock", func(tz string, fmtStr string) any { ... })
// after
tz, fmtStr := "UTC", time.Kitchen
root.RegisterComponent("clock", func(props map[string]any) any {
return renderClock(tz, fmtStr) // capture extras via closure
}) Defensive patterns
Strategy: validation
Validate before calling
t := reflect.TypeOf(cfunc)
if t != nil && t.Kind() == reflect.Func && t.NumIn() != 1 {
return fmt.Errorf("need exactly 1 arg, got %d", t.NumIn())
} Type guard
func isSingleArgFunc(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 signature invalid: %w", name, err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Component function must be a function
- Component function must return exactly 1 value
- Map argument must be map[string]any
- Component function argument must be map[string]any, struct,
- invalid number type %s
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/d2c349bb77daf560.
Report an issue: GitHub.