wavetermdev/waveterm · error
invalid map key type %s
Error message
invalid map key type %s
What it means
convertArgument rejects map-typed method parameters whose Go key type is not string. JSON objects always deserialize to map[string]any, so only map[string]X parameters are convertible; e.g. map[int]string or map[CustomKey]T can never be populated from a JSON RPC call and fail immediately.
Source
Thrown at pkg/service/service.go:233
return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
case reflect.Bool:
if jsonType.Kind() == reflect.Bool {
return jsonArg, nil
}
return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
if jsonType.Kind() == reflect.Float64 {
return convertNumber(argType, jsonArg.(float64))
}
return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
case reflect.Map:
if argType.Key().Kind() != reflect.String {
return nil, fmt.Errorf("invalid map key type %s", argType.Key())
}
if jsonType.Kind() != reflect.Map {
return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
}
return convertComplex(argType, jsonArg)
case reflect.Slice:
if jsonType.Kind() != reflect.Slice {
return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
}
return convertComplex(argType, jsonArg)
case reflect.Struct:
if jsonType.Kind() != reflect.Map {
return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
}
return convertComplex(argType, jsonArg)
View on GitHub (pinned to a4447c1563)
Solutions
- Change the service method signature to use map[string]T and convert keys (e.g. strconv.Atoi) inside the method body.
- Wrap the non-string-key map behind a string-keyed DTO type accepted by the RPC layer.
- If the key is a complex type, accept a slice of {key,value} pairs and rebuild the map server-side.
Example fix
// before
func (s *MyService) SetScores(m map[int]int) error
// after
func (s *MyService) SetScores(m map[string]int) error {
scores := map[int]int{}
for k, v := range m {
i, _ := strconv.Atoi(k)
scores[i] = v
}
...
} Defensive patterns
Strategy: validation
Validate before calling
if (typeof arg !== 'object' || Array.isArray(arg)) throw new Error('map param expects a JSON object with string keys'); Type guard
function isStringKeyedRecord(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); } Try / catch
try {
const rtn = await callService(svc, method, args);
if (rtn.error?.includes('invalid map key type')) throw new Error('method uses unsupported non-string map keys');
} catch (e) { /* switch to string-keyed DTO or report unsupported API */ } Prevention
- Only declare map[string]T parameters in RPC-exposed service methods.
- Convert non-string keys inside the method body, not in the signature.
- Review service signatures in code review for RPC compatibility.
When it happens
Trigger: A registered service method declares a parameter of kind reflect.Map whose key kind is not string (e.g. map[int]bool, map[uuid.UUID]T), and a client calls that method through CallService.
Common situations: Service authors writing methods with non-string map keys (numeric IDs, custom key structs) then exposing them over RPC; refactoring a method to use a richer key type without realizing the RPC bridge only supports string keys.
Related errors
- invalid special wave argument 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/0088e5dc30cd1506.
Report an issue: GitHub.