{"record":{"id":"948d2b19d171beb6","repo":"multica-ai/multica","slug":"read-chat-w","errorCode":null,"errorMessage":"read chat: %w","messagePattern":"read chat: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/multica/cmd_chat.go","lineNumber":110,"sourceCode":"\n\tq := url.Values{}\n\tif threadID != \"\" {\n\t\tq.Set(\"id\", threadID)\n\t}\n\tif limit > 0 {\n\t\tq.Set(\"limit\", strconv.Itoa(limit))\n\t}\n\tif before != \"\" {\n\t\tq.Set(\"before\", before)\n\t}\n\tpath := basePath\n\tif encoded := q.Encode(); encoded != \"\" {\n\t\tpath += \"?\" + encoded\n\t}\n\n\tvar resp map[string]any\n\tif err := client.GetJSON(ctx, path, &resp); err != nil {\n\t\treturn nil, fmt.Errorf(\"read chat: %w\", err)\n\t}\n\treturn resp, nil\n}\n\n// renderChatRead prints the response as JSON (default) or a table. The overview\n// table adds the thread columns so the agent can pick a thread_id to drill into.\nfunc renderChatRead(cmd *cobra.Command, resp map[string]any, overview bool) error {\n\toutput, _ := cmd.Flags().GetString(\"output\")\n\tif output != \"table\" {\n\t\treturn cli.PrintJSON(os.Stdout, resp)\n\t}\n\tif note := strVal(resp, \"note\"); note != \"\" {\n\t\tfmt.Fprintln(os.Stdout, note)\n\t\treturn nil\n\t}\n\tmsgs, _ := resp[\"messages\"].([]any)\n\tvar headers []string\n\tif overview {","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/multica/cmd_chat.go#L92-L128","documentation":"fetchChatRead wraps any failure of the chat-read HTTP request (GET basePath with optional ?id=<thread>&limit=<n>&before=<cursor>) as 'read chat: %w'. The wrapped error is the transport/status/decode failure from client.GetJSON — the chat endpoint returned non-2xx or the request never completed.","triggerScenarios":"Running `multica chat read` (or a thread variant) with an invalid/expired thread id, a malformed --before cursor, limit out of the server's accepted range, an unreachable server, or an unauthenticated session.","commonSituations":"Cursor (--before) copied from an older API version after pagination format changed; thread deleted between listing and read; dev server restarted losing in-memory state; stale auth token.","solutions":["Inspect the wrapped error for the HTTP status: 404 → thread id wrong or deleted; 400 → bad limit/before value; 401 → re-auth.","Re-run without --before/--limit to confirm the base listing works, then re-add paging params one at a time.","Verify the thread id exists in the overview listing (`chat read` without --id)."],"exampleFix":"# before\nmultica chat read --id <stale-thread-id> --before <old-cursor>\n# after\nmultica chat read --id <thread-id-from-listing>","handlingStrategy":"retry","validationCode":"# confirm the thread exists before reading with paging cursors\nmultica chat read --output json | jq -e --arg id \"$THREAD\" '.messages[]? | select(.thread_id == $id)' >/dev/null \\\n  || { echo \"thread $THREAD not found; refresh thread ids\" >&2; exit 2; }","typeGuard":null,"tryCatchPattern":"out, err := fetchChatRead(...)\nif err != nil && strings.Contains(err.Error(), \"read chat\") {\n    if statusIs(err, 401, 403) { reauth(); out, err = fetchChatRead(...) } // one retry after auth\n    if statusIs(err, 503)     { out, err = fetchChatRead(...) }          // one retry after backoff\n}","preventionTips":["Always take --before cursors from the immediately preceding response, never hard-code them.","Treat 404 on a thread id as 're-list threads' rather than retrying the same read."],"tags":["cli","api","chat","network","go"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}