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

  1. Add an explicit branch in convertSpecial (and convertSpecialForReturn) for the new special reflect.Type.
  2. Audit isSpecialWaveArgType so it only returns true for types convertSpecial handles.
  3. Reconcile merge changes to the RType variables (orefRType, waveObjRType, etc.) and their comparisons.
  4. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/b925fd2d7bab8ec7. Report an issue: GitHub.