wavetermdev/waveterm · error

cannot convert %T to %s

Error message

cannot convert %T to %s

What it means

convertWSCommand converts a JSON argument into a webcmd.WSCommand. The JSON value must be a map[string]any; any other JSON type (string, number, array, nil) cannot represent a command and triggers 'cannot convert %T to %s'.

Source

Thrown at pkg/service/service.go:104

	return nil, fmt.Errorf("invalid number type %s", argType)
}

func convertComplex(argType reflect.Type, jsonArg any) (any, error) {
	nativeArgVal := reflect.New(argType)
	err := utilfn.DoMapStructure(nativeArgVal.Interface(), jsonArg)
	if err != nil {
		return nil, err
	}
	return nativeArgVal.Elem().Interface(), nil
}

func isSpecialWaveArgType(argType reflect.Type) bool {
	return argType == waveObjRType || argType == waveObjSliceRType || argType == waveObjMapRType || argType == wsCommandRType
}

func convertWSCommand(argType reflect.Type, jsonArg any) (any, error) {
	if _, ok := jsonArg.(map[string]any); !ok {
		return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
	}
	cmd, err := webcmd.ParseWSCommandMap(jsonArg.(map[string]any))
	if err != nil {
		return nil, fmt.Errorf("error parsing command map: %w", err)
	}
	return cmd, nil
}

func convertSpecial(argType reflect.Type, jsonArg any) (any, error) {
	jsonType := reflect.TypeOf(jsonArg)
	if argType == orefRType {
		if jsonType.Kind() != reflect.String {
			return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
		}
		oref, err := waveobj.ParseORef(jsonArg.(string))
		if err != nil {
			return nil, fmt.Errorf("invalid oref string: %v", err)
		}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Pass the command as a JSON object with the expected WSCommand fields (command, args, etc.).
  2. Wrap string command names into the proper object shape before invoking.
  3. Ensure client and server versions agree on the WSCommand argument shape.

Example fix

// before
invokeRpc("run-command", "run:shell")
// after
invokeRpc("run-command", map[string]any{"command": "run", "args": []any{"shell"}})
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := arg.(map[string]any); !ok {
    return fmt.Errorf("WSCommand arg must be a JSON object, got %T", arg)
}

Type guard

func isWSCommandArg(v any) bool {
    _, ok := v.(map[string]any)
    return ok
}

Prevention

When it happens

Trigger: An RPC method takes a WSCommand parameter but the caller passes a string (e.g. a command name) or array instead of a JSON object like {"command":"run","args":[...]}.

Common situations: Frontend sends the command as a serialized string instead of an object; callers confuse WSCommand with a command string ID; client/server schema drift.

Related errors


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