{"record":{"id":"f28769da689e2a2d","repo":"wavetermdev/waveterm","slug":"cannot-convert-special-return-value-v","errorCode":null,"errorMessage":"cannot convert special return value: %v","messagePattern":"cannot convert special return value: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/service.go","lineNumber":297,"sourceCode":"\t}\n\tfor _, val := range rtnVals {\n\t\tif isNilable(val) && val.IsNil() {\n\t\t\tcontinue\n\t\t}\n\t\tvalType := val.Type()\n\t\tif valType == errorRType {\n\t\t\trtn.Error = val.Interface().(error).Error()\n\t\t\tcontinue\n\t\t}\n\t\tif valType == updatesRType {\n\t\t\t// has a special MarshalJSON method\n\t\t\trtn.Updates = val.Interface().([]waveobj.WaveObjUpdate)\n\t\t\tcontinue\n\t\t}\n\t\tif isSpecialWaveArgType(valType) {\n\t\t\tjsonVal, err := convertSpecialForReturn(valType, val.Interface())\n\t\t\tif err != nil {\n\t\t\t\trtn.Error = fmt.Errorf(\"cannot convert special return value: %v\", err).Error()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\trtn.Data = jsonVal\n\t\t\tcontinue\n\t\t}\n\t\trtn.Data = val.Interface()\n\t}\n\tif rtn.Error == \"\" {\n\t\trtn.Success = true\n\t}\n\treturn rtn\n}\n\nfunc webErrorRtn(err error) *WebReturnType {\n\treturn &WebReturnType{\n\t\tError: err.Error(),\n\t}\n}","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/service.go#L279-L315","documentation":"Set on the WebReturnType.Error field when convertSpecialForReturn fails to serialize a special Wave return value (WaveObj, []WaveObj, or map[string]WaveObj) back to JSON. This usually means waveobj.ToJsonMap failed on the object (bad/missing otype or missing required fields), or a method returned a nil/invalid object inside a slice or map.","triggerScenarios":"A service method returns waveobj.WaveObj (or slice/map of them) whose ToJsonMap conversion errors — e.g. an object with an empty OType/OID, or a WaveObj implementation failing serialization. The error is stored in rtn.Error rather than panicking, and the call is reported as failed to the client.","commonSituations":"Constructing WaveObj instances manually with missing otype/oid; custom obj types not registered with the waveobj schema; returning objects from a different waveobj package version than the serializer expects.","solutions":["Inspect the wrapped %v detail in rtn.Error — it carries the underlying ToJsonMap failure reason.","Ensure returned WaveObj values have valid OType and OID set before returning.","Register custom object types properly so FromJsonMap/ToJsonMap round-trip works.","Return an error alongside the value so failures surface cleanly instead of only the conversion error."],"exampleFix":"// before\nfunc (s *Svc) GetObj() waveobj.WaveObj {\n    return &MyObj{} // missing OType/OID\n}\n\n// after\nfunc (s *Svc) GetObj() (waveobj.WaveObj, error) {\n    return &MyObj{OType: \"myobj\", OID: genId()}, nil\n}","handlingStrategy":"try-catch","validationCode":"// server-side pre-check before returning\nif (obj == nil || reflect.ValueOf(obj).IsNil() || obj.GetOType() == \"\") {\n    return nil, fmt.Errorf(\"invalid WaveObj: missing otype\")\n}","typeGuard":"function isValidReturn(rtn) { return rtn != null && !('error' in rtn && rtn.error); }","tryCatchPattern":"const rtn = await callService(svc, method, args);\nif (rtn.error?.startsWith('cannot convert special return value')) {\n  // inspect rtn.error detail; re-request or surface serialization failure\n}","preventionTips":["Always set OType/OID on returned WaveObj values.","Round-trip test custom obj types with ToJsonMap/FromJsonMap in CI.","Return (value, error) from service methods so failures are explicit."],"tags":["rpc","serialization","waveobj","return-value"],"backgroundTag":"rpc-return-serialization-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}