wavetermdev/waveterm · error
invalid special wave argument type %s
Error message
invalid special wave argument type %s
What it means
convertSpecial only knows how to decode the registered special argument types (waveobj.ORef, webcmd.WSCommand, waveobj.WaveObj, []waveobj.WaveObj, map[string]waveobj.WaveObj). If isSpecialWaveArgType/convertSpecial is reached with a reflect.Type outside that set, it reports the unsupported type. This indicates an internal inconsistency: a type was classified as special but has no decoding branch.
Source
Thrown at pkg/service/service.go:168
if jsonType.Kind() != reflect.Map {
return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
}
mapArg := jsonArg.(map[string]any)
nativeMap := make(map[string]waveobj.WaveObj)
for key, elem := range mapArg {
elemMap, ok := elem.(map[string]any)
if !ok {
return nil, fmt.Errorf("cannot convert %T to %s (key %s is not a map, is %T)", jsonArg, waveObjMapRType, key, elem)
}
nativeObj, err := waveobj.FromJsonMap(elemMap)
if err != nil {
return nil, fmt.Errorf("cannot convert %T to %s (key %s) error: %v", jsonArg, waveObjMapRType, key, err)
}
nativeMap[key] = nativeObj
}
return nativeMap, nil
} else {
return nil, fmt.Errorf("invalid special wave argument type %s", argType)
}
}
func convertSpecialForReturn(argType reflect.Type, nativeArg any) (any, error) {
if argType == waveObjRType {
return waveobj.ToJsonMap(nativeArg.(waveobj.WaveObj))
} else if argType == waveObjSliceRType {
nativeSlice := nativeArg.([]waveobj.WaveObj)
jsonSlice := make([]map[string]any, len(nativeSlice))
for idx, elem := range nativeSlice {
elemMap, err := waveobj.ToJsonMap(elem)
if err != nil {
return nil, err
}
jsonSlice[idx] = elemMap
}
return jsonSlice, nil
} else if argType == waveObjMapRType {View on GitHub (pinned to a4447c1563)
Solutions
- Add an explicit branch in convertSpecial (and convertSpecialForReturn) for the new special reflect.Type.
- Audit isSpecialWaveArgType so it only returns true for types convertSpecial handles.
- Reconcile merge changes to the RType variables (orefRType, waveObjRType, etc.) and their comparisons.
- As a caller, avoid declaring service-method params of custom types; use the supported special types or plain JSON types.
Example fix
// before (convertSpecial)
} else {
return nil, fmt.Errorf("invalid special wave argument type %s", argType)
}
// after
} else if argType == myNewRType {
return decodeMyNewType(jsonArg)
} else {
return nil, fmt.Errorf("invalid special wave argument type %s", argType)
} Defensive patterns
Strategy: fallback
Validate before calling
const SUPPORTED_SPECIALS = ['waveobj.ORef', 'webcmd.WSCommand', 'waveobj.WaveObj', '[]waveobj.WaveObj', 'map[string]waveobj.WaveObj'];
// server-side guard when adding types: if isSpecialWaveArgType(t) && !handledByConvertSpecial(t) { panic('unhandled special type: ' + t) } Try / catch
err := convertSpecial(argType, jsonArg)
if err != nil { log.Printf("special arg conversion failed for %s: %v", argType, err); return webErrorRtn(err) } Prevention
- Extend convertSpecial and convertSpecialForReturn together with isSpecialWaveArgType.
- Add a unit test asserting every special type has a decode branch.
- Avoid ad-hoc custom types in service-method signatures.
- Review RType comparisons after refactors/merges.
When it happens
Trigger: Calling CallService on a method whose parameter type was newly added to isSpecialWaveArgType without a matching branch in convertSpecial, or a refactor that changed/renamed the special RTypes (orefRType, wsCommandRType, waveObjRType, waveObjSliceRType, waveObjMapRType).
Common situations: A developer adds a new special argument type to the RPC layer but forgets the convertSpecial branch; merge conflicts that drop a branch; type alias changes making a comparison fail.
Related errors
- invalid map key type %s
- invalid pointer type %s
- invalid argument type %s
- invalid number type %s
- invalid method: %s.%s
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/b925fd2d7bab8ec7.
Report an issue: GitHub.