Description
An ACP client cannot resume a session it created with session/new: the id session/new returns is not resolvable by session/load, while session/list reports the bare form that is.
Three observations from one ACP server, all in a throwaway CODEWHALE_HOME (no turn sent, no model call, no real session store read or written):
session/new returns a provider-prefixed id.
session/list returns bare uuids.
session/load accepts only the bare form. The prefixed form fails with -32602, and it still fails when a session file is named exactly like the prefixed id.
An ACP client has no id for a session it just created other than the one session/new returned, so a client that persists and replays that id — the normal thing to do — can never resume the session.
Steps to reproduce
Everything below runs against a scratch home; nothing outside it is touched.
export CODEWHALE_HOME=$(mktemp -d)
ac() { printf '%s\n' "$@" | codewhale serve --acp; }
1. What session/new advertises:
ac '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1,"clientCapabilities":{"fs":{"readTextFile":true,"writeTextFile":true}}}}' \
'{"jsonrpc":"2.0","id":2,"method":"session/new","params":{"cwd":"<any-directory>","mcpServers":[]}}'
{"jsonrpc":"2.0","id":2,"result":{"sessionId":"codewhale-95bb3fa8-8784-4eed-b34a-59072e9e9823","modes":{...},"models":{...}}}
Note the codewhale- prefix on the id.
2. What session/list advertises for existing sessions:
{"jsonrpc":"2.0","id":2,"result":{"sessions":[{"sessionId":"c45e7916-ab6a-4585-8d09-d3649fd92f38","title":"...","cwd":"...","createdAt":"...","updatedAt":"...","messageCount":232}, ...]}}
Bare uuid, no prefix.
3. What session/load accepts. With exactly one persisted session file present, 415488d4-14a0-46ff-8477-7a3989a36de2.json:
bare id — succeeds:
{"jsonrpc":"2.0","id":2,"result":{"sessionId":"415488d4-14a0-46ff-8477-7a3989a36de2","modes":{...},"models":{...},"configOptions":[...]}}
the same id written the way session/new writes it — fails:
{"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"could not load session codewhale-415488d4-14a0-46ff-8477-7a3989a36de2: No session found with prefix: codewhale-415488d4-14a0-46ff-8477-7a3989a36de2"}}
Adding a second file named codewhale-415488d4-14a0-46ff-8477-7a3989a36de2.json and repeating the prefixed request gives the identical error, so this is not merely a filename-naming mismatch:
415488d4-14a0-46ff-8477-7a3989a36de2.json
codewhale-415488d4-14a0-46ff-8477-7a3989a36de2.json
{"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"could not load session codewhale-415488d4-14a0-46ff-8477-7a3989a36de2: No session found with prefix: codewhale-415488d4-14a0-46ff-8477-7a3989a36de2"}}
Expected behavior
One of:
session/new returns the id session/load resolves — the bare uuid session/list reports — or
session/load accepts the prefixed form session/new hands out (strip a known <provider>- prefix before resolving), or
- the resolver recognises the prefixed form and, when the remainder resolves to an existing session, says so instead of reporting a plain not-found.
Actual behavior
The advertised id is unresolvable. A client that round-trips it gets -32602 ... No session found with prefix: codewhale-<uuid>.
Impact
Any ACP client that persists session ids (Paseo, editors) cannot resume the CodeWhale sessions it created.
It also does not stay contained. A client that polls a timeline for an agent whose resume fails re-attempts the resume on every poll, so the misadvertised id turns into a permanent error loop. In the case that led me here, one level-50 entry was written every ~30s for over five hours, and the affected timeline request was pinned at ~390 ms p50 because every poll paid for a failing ACP resume. (That client-side behaviour is reported separately; the trigger is this id mismatch.)
Environment
- OS: Linux 7.2.4-4-liquorix-amd64 (x64)
- codewhale version: 0.9.12 (dcd4c20)
- Install method: pnpm global. The package downloads the GitHub release binary (
bin/downloads/codewhale.source = source=github, base=https://github.com/Hmbown/CodeWhale/releases/download/v0.9.12/)
codewhale doctor summary:
Version Information:
codewhale-tui: 0.9.12 (dcd4c200f72f)
rust: rustc 1.94.0 (4a4ef493e 2026-03-02)
Configuration:
config.toml found at ~/.codewhale/config.toml
Resolved User Paths (read-only):
sessions: ~/.codewhale/sessions
- Model/provider: not exercised —
initialize / session/new / session/load / session/list only, no turn sent
- Terminal app: n/a (stdio ACP client, not the TUI)
- Shell: bash
Logs, screenshots, or recordings
Raw ACP responses are inlined in the steps above. For the shape of the failure as a client sees it, one raw daemon-side line (Paseo 0.8.0) from the episode above, with ids and paths replaced by placeholders:
{"level":50,"time":<ts>,"hostname":"<host>","daemonVersion":"0.8.0","module":"websocket-server","connectionId":"<conn>","transport":"direct","peer":"loopback","clientId":"<client>","module":"session","sessionId":"<client-session>","err":{"type":"Error","message":"could not load session codewhale-14a4e0de-...: No session found with prefix: codewhale-14a4e0de-...","stack":"ACPRequestError: could not load session codewhale-14a4e0de-...: No session found with prefix: codewhale-14a4e0de-...\n at toACPRequestError (.../acp-agent.js:66:18)\n at ACPAgentSession.runACPRequest (.../acp-agent.js:1878:19)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n at async ACPAgentSession.initializeResumedSession (.../acp-agent.js:1070:34)\n at async GenericACPAgentClient.resumeSession (.../acp-agent.js:503:9)\n at async Object.resumeSession (.../provider-registry.js:272:107)\n at async AgentManager.resumeAgentFromPersistenceInternal (.../agent-manager.js:724:25)","name":"ACPRequestError"},"agentId":"<agent-id>","msg":"Failed to handle fetch_agent_timeline_request"}
One caveat, for honesty. I did not send a turn, so I did not observe a session created by session/new end-to-end (persisted, then resumed). The link between step 1 and step 3 is established at the interface — the form session/new returns versus the only form session/load accepts — both directly observed. Steps 1, 2 and 3 are raw command output, not inference.
Description
An ACP client cannot resume a session it created with
session/new: the idsession/newreturns is not resolvable bysession/load, whilesession/listreports the bare form that is.Three observations from one ACP server, all in a throwaway
CODEWHALE_HOME(no turn sent, no model call, no real session store read or written):session/newreturns a provider-prefixed id.session/listreturns bare uuids.session/loadaccepts only the bare form. The prefixed form fails with-32602, and it still fails when a session file is named exactly like the prefixed id.An ACP client has no id for a session it just created other than the one
session/newreturned, so a client that persists and replays that id — the normal thing to do — can never resume the session.Steps to reproduce
Everything below runs against a scratch home; nothing outside it is touched.
1. What
session/newadvertises:{"jsonrpc":"2.0","id":2,"result":{"sessionId":"codewhale-95bb3fa8-8784-4eed-b34a-59072e9e9823","modes":{...},"models":{...}}}Note the
codewhale-prefix on the id.2. What
session/listadvertises for existing sessions:{"jsonrpc":"2.0","id":2,"result":{"sessions":[{"sessionId":"c45e7916-ab6a-4585-8d09-d3649fd92f38","title":"...","cwd":"...","createdAt":"...","updatedAt":"...","messageCount":232}, ...]}}Bare uuid, no prefix.
3. What
session/loadaccepts. With exactly one persisted session file present,415488d4-14a0-46ff-8477-7a3989a36de2.json:bare id — succeeds:
{"jsonrpc":"2.0","id":2,"result":{"sessionId":"415488d4-14a0-46ff-8477-7a3989a36de2","modes":{...},"models":{...},"configOptions":[...]}}the same id written the way
session/newwrites it — fails:{"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"could not load session codewhale-415488d4-14a0-46ff-8477-7a3989a36de2: No session found with prefix: codewhale-415488d4-14a0-46ff-8477-7a3989a36de2"}}Adding a second file named
codewhale-415488d4-14a0-46ff-8477-7a3989a36de2.jsonand repeating the prefixed request gives the identical error, so this is not merely a filename-naming mismatch:{"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"could not load session codewhale-415488d4-14a0-46ff-8477-7a3989a36de2: No session found with prefix: codewhale-415488d4-14a0-46ff-8477-7a3989a36de2"}}Expected behavior
One of:
session/newreturns the idsession/loadresolves — the bare uuidsession/listreports — orsession/loadaccepts the prefixed formsession/newhands out (strip a known<provider>-prefix before resolving), orActual behavior
The advertised id is unresolvable. A client that round-trips it gets
-32602 ... No session found with prefix: codewhale-<uuid>.Impact
Any ACP client that persists session ids (Paseo, editors) cannot resume the CodeWhale sessions it created.
It also does not stay contained. A client that polls a timeline for an agent whose resume fails re-attempts the resume on every poll, so the misadvertised id turns into a permanent error loop. In the case that led me here, one level-50 entry was written every ~30s for over five hours, and the affected timeline request was pinned at ~390 ms p50 because every poll paid for a failing ACP resume. (That client-side behaviour is reported separately; the trigger is this id mismatch.)
Environment
bin/downloads/codewhale.source=source=github,base=https://github.com/Hmbown/CodeWhale/releases/download/v0.9.12/)codewhale doctorsummary:initialize/session/new/session/load/session/listonly, no turn sentLogs, screenshots, or recordings
Raw ACP responses are inlined in the steps above. For the shape of the failure as a client sees it, one raw daemon-side line (Paseo 0.8.0) from the episode above, with ids and paths replaced by placeholders:
One caveat, for honesty. I did not send a turn, so I did not observe a session created by
session/newend-to-end (persisted, then resumed). The link between step 1 and step 3 is established at the interface — the formsession/newreturns versus the only formsession/loadaccepts — both directly observed. Steps 1, 2 and 3 are raw command output, not inference.