{"record":{"id":"a354262290e18d22","repo":"wavetermdev/waveterm","slug":"cannot-convert-t-to-s-idx-d-is-not-a-map-is","errorCode":null,"errorMessage":"cannot convert %T to %s (idx %d is not a map, is %T)","messagePattern":"cannot convert %T to (.+?) \\(idx (.+?) is not a map, is %T\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/service.go","lineNumber":140,"sourceCode":"\t\t}\n\t\treturn oref, nil\n\t} else if argType == wsCommandRType {\n\t\treturn convertWSCommand(argType, jsonArg)\n\t} else if argType == waveObjRType {\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 waveobj.FromJsonMap(jsonArg.(map[string]any))\n\t} else if argType == waveObjSliceRType {\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\tsliceArg := jsonArg.([]any)\n\t\tnativeSlice := make([]waveobj.WaveObj, len(sliceArg))\n\t\tfor idx, elem := range sliceArg {\n\t\t\telemMap, ok := elem.(map[string]any)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot convert %T to %s (idx %d is not a map, is %T)\", jsonArg, waveObjSliceRType, idx, elem)\n\t\t\t}\n\t\t\tnativeObj, err := waveobj.FromJsonMap(elemMap)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot convert %T to %s (idx %d) error: %v\", jsonArg, waveObjSliceRType, idx, err)\n\t\t\t}\n\t\t\tnativeSlice[idx] = nativeObj\n\t\t}\n\t\treturn nativeSlice, nil\n\t} else if argType == waveObjMapRType {\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\tmapArg := jsonArg.(map[string]any)\n\t\tnativeMap := make(map[string]waveobj.WaveObj)\n\t\tfor key, elem := range mapArg {\n\t\t\telemMap, ok := elem.(map[string]any)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot convert %T to %s (key %s is not a map, is %T)\", jsonArg, waveObjMapRType, key, elem)","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/service.go#L122-L158","documentation":"When a service method takes []waveobj.WaveObj, convertSpecial first checks the whole argument is a JSON array, then iterates elements requiring each to be a JSON object. This error fires when element idx of the array is not an object (string, number, bool, null handled earlier, or nested array), reporting both the index and the offending element's Go type.","triggerScenarios":"An RPC call with a WaveObj slice argument where at least one array element is a scalar or nested array instead of a serialized WaveObj map — e.g. sending [\"block:default:abc\"] (oref strings) instead of [{\"otype\":...}].","commonSituations":"Frontend passing lists of object IDs/orefs instead of full objects; an API change where the endpoint now expects full objects but old callers still send IDs; JSON payloads built by string concatenation producing malformed arrays.","solutions":["Fix the array element at the reported idx to be a full serialized WaveObj object.","Map any list of orefs/IDs to their full WaveObj representations before calling the RPC.","Log the payload on the client to confirm array contents match the new schema.","Check for a version skew between frontend caller and backend service method signatures."],"exampleFix":"// before\ncallService(\"objservice\", \"UpdateObjects\", [\"block:default:abc\"])\n// after\ncallService(\"objservice\", \"UpdateObjects\", [await rpcGetWaveObjJson(\"block:default:abc\")])","handlingStrategy":"validation","validationCode":"function isWaveObjArray(v) { return Array.isArray(v) && v.every(e => e && typeof e === 'object' && !Array.isArray(e) && typeof e.otype === 'string'); }\nif (!isWaveObjArray(arg)) throw new Error('every array element must be a serialized WaveObj');","typeGuard":"const isWaveObjElem = (e) => typeof e === 'object' && e !== null && !Array.isArray(e);","tryCatchPattern":"try { return await callService(svc, method, args); } catch (e) { const m = String(e).match(/idx (\\d+) is not a map, is (\\S+)/); if (m) { console.error('bad WaveObj slice element at index', m[1], 'type', m[2]); } throw e; }","preventionTips":["Map lists of IDs/orefs to full objects before array-typed RPCs.","Validate each array element is a plain object before sending.","Log full payloads when element-level conversion errors occur.","Regenerate client bindings when server signatures change."],"tags":["rpc","type-conversion","array","waveobj"],"backgroundTag":"json-type-mismatch","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}