{"record":{"id":"9576a8103b60ac78","repo":"chenhg5/cc-connect","slug":"decode-s-response-w","errorCode":null,"errorMessage":"decode %s response: %w","messagePattern":"decode (.+?) response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/codex/appserver_session.go","lineNumber":1646,"sourceCode":"\tremaining := time.Until(deadline)\n\tif remaining <= 0 {\n\t\ts.pendingMu.Lock()\n\t\tdelete(s.pending, id)\n\t\ts.pendingMu.Unlock()\n\t\treturn fmt.Errorf(\"%s timed out\", method)\n\t}\n\n\ttimer := time.NewTimer(remaining)\n\tdefer timer.Stop()\n\tctxDone := s.contextDone()\n\tselect {\n\tcase resp := <-ch:\n\t\tif resp.Error != nil {\n\t\t\treturn fmt.Errorf(\"%s\", strings.TrimSpace(resp.Error.Message))\n\t\t}\n\t\tif out != nil {\n\t\t\tif err := json.Unmarshal(resp.Result, out); err != nil {\n\t\t\t\treturn fmt.Errorf(\"decode %s response: %w\", method, err)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\tcase <-ctxDone:\n\t\treturn s.contextErr()\n\tcase <-timer.C:\n\t\ts.pendingMu.Lock()\n\t\tdelete(s.pending, id)\n\t\ts.pendingMu.Unlock()\n\t\treturn fmt.Errorf(\"%s timed out\", method)\n\t}\n}\n\nfunc (s *appServerSession) writeJSONWithTimeout(method string, v any, timeout time.Duration) error {\n\tdone := make(chan error, 1)\n\tgo func() {\n\t\tdone <- s.writeJSON(v)\n\t}()","sourceCodeStart":1628,"sourceCodeEnd":1664,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/codex/appserver_session.go#L1628-L1664","documentation":"Returned when the app-server's JSON-RPC result for a request cannot be unmarshaled into the caller-provided `out` value: `fmt.Errorf(\"decode %s response: %w\", method, err)`. This indicates the response shape does not match the expected Go struct — usually a codex protocol version change rather than a runtime failure.","triggerScenarios":"A successful (non-error) JSON-RPC response arrives but `json.Unmarshal(resp.Result, out)` fails — e.g. field type changed, new schema, null where a struct is expected, or a wrong `out` type passed by the caller.","commonSituations":"Codex CLI upgraded and response fields renamed/retyped; decoding into the wrong struct for the method; server returning null result for methods expected to return objects; proxy/middleware mangling the response JSON.","solutions":["Pin/upgrade cc-connect to a version matching your installed codex CLI version.","Log `string(resp.Result)` for the failing method to compare actual vs expected schema.","Check that the `out` argument passed to `request()` matches the method's documented response type.","Downgrade codex if you must stay on the current cc-connect release.","Handle null results defensively by decoding into json.RawMessage first."],"exampleFix":"// before: assume old schema\nvar out threadStartResponse\ns.request(\"thread/start\", params, &out)\n\n// after: inspect raw payload when decoding fails\nvar raw json.RawMessage\nif err := s.request(\"thread/start\", params, &raw); err != nil { ... }\nslog.Debug(\"codex raw response\", \"body\", string(raw))","handlingStrategy":"type-guard","validationCode":"// decode into RawMessage first to detect shape drift\nvar raw json.RawMessage\nif err := sess.request(\"thread/start\", params, &raw); err != nil { return err }\nvar probe map[string]json.RawMessage\nreturn json.Unmarshal(raw, &probe) // inspect keys before strict decode","typeGuard":"func decodeAs[T any](raw json.RawMessage) (*T, error) {\n    var v T\n    if err := json.Unmarshal(raw, &v); err != nil {\n        return nil, fmt.Errorf(\"schema mismatch: %w\", err)\n    }\n    return &v, nil\n}","tryCatchPattern":"if err := json.Unmarshal(resp.Result, out); err != nil {\n    slog.Error(\"codex response schema drift\", \"method\", method, \"body\", string(resp.Result))\n    return fmt.Errorf(\"decode %s response: %w\", method, err)\n}","preventionTips":["Upgrade cc-connect whenever you upgrade codex CLI.","Snapshot real responses in tests to catch schema drift.","Log raw response bodies on decode failure.","Use lenient types (json.RawMessage, pointers) for evolving fields."],"tags":["codex","json","unmarshal","schema-mismatch"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}