{"record":{"id":"5f93c2bf91126aca","repo":"chenhg5/cc-connect","slug":"s-5f93c2","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/codex/appserver_session.go","lineNumber":1170,"sourceCode":"\t\t\ts.completeTurn()\n\t\t}\n\n\tcase \"account/rateLimits/updated\":\n\t\tvar notif appServerRateLimitsResponse\n\t\tif err := json.Unmarshal(paramsRaw, &notif); err == nil {\n\t\t\ts.storeUsage(mapAppServerRateLimits(notif))\n\t\t}\n\n\tcase \"thread/tokenUsage/updated\":\n\t\tvar notif appServerThreadTokenUsageNotification\n\t\tif err := json.Unmarshal(paramsRaw, &notif); err == nil {\n\t\t\ts.storeContextUsage(mapAppServerTokenUsage(notif))\n\t\t}\n\n\tcase \"error\":\n\t\tvar notif errorNotification\n\t\tif err := json.Unmarshal(paramsRaw, &notif); err == nil && strings.TrimSpace(notif.Message) != \"\" {\n\t\t\ts.emitError(fmt.Errorf(\"%s\", notif.Message))\n\t\t}\n\t}\n}\n\nfunc (s *appServerSession) handleItemStarted(item map[string]any) {\n\titemType, _ := item[\"type\"].(string)\n\tif itemType == \"\" {\n\t\treturn\n\t}\n\n\tswitch itemType {\n\tcase \"agentMessage\", \"reasoning\", \"userMessage\", \"plan\", \"hookPrompt\", \"contextCompaction\":\n\t\treturn\n\t}\n\n\ts.flushPendingAsThinking()\n\n\tswitch itemType {","sourceCodeStart":1152,"sourceCodeEnd":1188,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/codex/appserver_session.go#L1152-L1188","documentation":"The codex app-server sends a standalone `error` JSON-RPC notification; the adapter unmarshals its `message` field and emits it verbatim as a core.EventError on the session's event stream. Unlike error 160, this text comes directly from codex, so its content varies (e.g. stream errors, auth failures). It is a forwarded upstream error, not one composed by this library.","triggerScenarios":"A JSON-RPC notification with method `error` and a `message` field is received on the app-server notification channel while a session is live; the message is non-empty after trimming.","commonSituations":"Model/provider stream failures mid-turn; codex auth token expiring; backend 5xx surfacing as error notifications; network interruption between codex and its model backend; rate limit rejections.","solutions":["Read the emitted event's Error text — it is the codex backend's own message and states the actual cause.","If it mentions auth, re-run `codex login` or refresh credentials.","If it mentions rate limits/quota, wait or reduce request frequency.","Check codex CLI and cc-connect versions for protocol compatibility.","Retry the turn if the message indicates a transient stream error."],"exampleFix":"// caller side: surface forwarded codex errors to the user\nfor ev := range sess.Events() {\n    if ev.Type == core.EventError {\n        slog.Warn(\"codex reported error\", \"err\", ev.Error)\n        // before: silently ignore\n        // after: reply with ev.Error text or retry\n    }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"for ev := range sess.Events() {\n    if ev.Type == core.EventError {\n        switch {\n        case strings.Contains(ev.Error.Error(), \"auth\"):\n            relogin()\n        case strings.Contains(ev.Error.Error(), \"rate limit\"):\n            backoff()\n        default:\n            logAndSurface(ev.Error)\n        }\n    }\n}","preventionTips":["Handle EventError events on the session stream — they carry codex's own diagnostics.","Refresh codex credentials periodically for long-running daemons.","Respect rate limits when driving many turns.","Log the raw message before mapping to user-facing text."],"tags":["codex","app-server","json-rpc","upstream-error"],"backgroundTag":"upstream-api-error","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}