{"record":{"id":"a9c39f0e9fdec787","repo":"wavetermdev/waveterm","slug":"cannot-convert-t-to-s-idx-d-error-v","errorCode":null,"errorMessage":"cannot convert %T to %s (idx %d) error: %v","messagePattern":"cannot convert %T to (.+?) \\(idx (.+?)\\) error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/service.go","lineNumber":144,"sourceCode":"\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)\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 (key %s) error: %v\", jsonArg, waveObjMapRType, key, err)","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/service.go#L126-L162","documentation":"After each element of a []waveobj.WaveObj argument passes the is-a-map check, it is decoded with waveobj.FromJsonMap. If FromJsonMap fails (e.g. missing/invalid otype, unknown object type, malformed fields), convertSpecial wraps the inner error with the argument type and element index, so a single bad element fails the whole call.","triggerScenarios":"An RPC call whose WaveObj-slice argument contains an object at idx that FromJsonMap rejects: missing \"otype\"/\"oid\" keys, an unrecognized otype string, or otype-specific fields failing validation.","commonSituations":"Hand-crafted or partially-populated object payloads (e.g. {\"otype\":\"block\"} with no oid); an otype added in a newer frontend but unknown to an older backend; renamed or removed object fields after a schema update.","solutions":["Read the wrapped inner error (%v) for the concrete FromJsonMap failure and fix the element at the reported idx accordingly.","Ensure each element has valid \"otype\" and \"oid\" fields for a registered WaveObj type.","Align frontend/backend versions so the otype and field schema match.","Generate payloads via the client SDK's ToJsonMap/serialization helpers rather than hand-writing them."],"exampleFix":"// before\ncallService(\"objservice\", \"UpdateObjects\", [{ \"otype\": \"block\" }]) // missing oid\n// after\ncallService(\"objservice\", \"UpdateObjects\", [{ \"otype\": \"block\", \"oid\": \"abc123\", \"meta\": {}, \"view\": {} }])","handlingStrategy":"validation","validationCode":"function validateWaveObjs(arr) { arr.forEach((e, i) => { if (typeof e.otype !== 'string' || typeof e.oid !== 'string') throw new Error('element ' + i + ' missing otype/oid'); }); }","typeGuard":"function hasWaveObjMeta(e) { return e && typeof e.otype === 'string' && typeof e.oid === 'string'; }","tryCatchPattern":"try { return await callService(svc, method, args); } catch (e) { const m = String(e).match(/idx (\\d+)\\) error: (.*)$/); if (m) { console.error('WaveObj at index ' + m[1] + ' failed decode: ' + m[2]); } throw e; }","preventionTips":["Always include valid otype and oid in serialized objects.","Construct payloads with the SDK serializer, not by hand.","Keep otype schemas version-aligned between client and server.","Capture and surface the wrapped inner error when debugging."],"tags":["rpc","deserialization","waveobj","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}