{"record":{"id":"0088e5dc30cd1506","repo":"wavetermdev/waveterm","slug":"invalid-map-key-type-s","errorCode":null,"errorMessage":"invalid map key type %s","messagePattern":"invalid map key type (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/service.go","lineNumber":233,"sourceCode":"\t\treturn nil, fmt.Errorf(\"cannot convert %T to %s\", jsonArg, argType)\n\n\tcase reflect.Bool:\n\t\tif jsonType.Kind() == reflect.Bool {\n\t\t\treturn jsonArg, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"cannot convert %T to %s\", jsonArg, argType)\n\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,\n\t\treflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,\n\t\treflect.Float32, reflect.Float64:\n\t\tif jsonType.Kind() == reflect.Float64 {\n\t\t\treturn convertNumber(argType, jsonArg.(float64))\n\t\t}\n\t\treturn nil, fmt.Errorf(\"cannot convert %T to %s\", jsonArg, argType)\n\n\tcase reflect.Map:\n\t\tif argType.Key().Kind() != reflect.String {\n\t\t\treturn nil, fmt.Errorf(\"invalid map key type %s\", argType.Key())\n\t\t}\n\t\tif jsonType.Kind() != reflect.Map {\n\t\t\treturn nil, fmt.Errorf(\"cannot convert %T to %s\", jsonArg, argType)\n\t\t}\n\t\treturn convertComplex(argType, jsonArg)\n\n\tcase reflect.Slice:\n\t\tif jsonType.Kind() != reflect.Slice {\n\t\t\treturn nil, fmt.Errorf(\"cannot convert %T to %s\", jsonArg, argType)\n\t\t}\n\t\treturn convertComplex(argType, jsonArg)\n\n\tcase reflect.Struct:\n\t\tif jsonType.Kind() != reflect.Map {\n\t\t\treturn nil, fmt.Errorf(\"cannot convert %T to %s\", jsonArg, argType)\n\t\t}\n\t\treturn convertComplex(argType, jsonArg)\n","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/service.go#L215-L251","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nfunc (s *MyService) SetScores(m map[int]int) error\n\n// after\nfunc (s *MyService) SetScores(m map[string]int) error {\n    scores := map[int]int{}\n    for k, v := range m {\n        i, _ := strconv.Atoi(k)\n        scores[i] = v\n    }\n    ...\n}","handlingStrategy":"validation","validationCode":"if (typeof arg !== 'object' || Array.isArray(arg)) throw new Error('map param expects a JSON object with string keys');","typeGuard":"function isStringKeyedRecord(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }","tryCatchPattern":"try {\n  const rtn = await callService(svc, method, args);\n  if (rtn.error?.includes('invalid map key type')) throw new Error('method uses unsupported non-string map keys');\n} catch (e) { /* switch to string-keyed DTO or report unsupported API */ }","preventionTips":["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."],"tags":["rpc","map-key","reflection","unsupported-type"],"backgroundTag":"rpc-unsupported-parameter-type","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}