[Bug] Resumed sessions reject all sends with restoreWarning (ZCODE_RUNTIME_MODEL_UNAVAILABLE) — workspace-key normalization arms the guard on every resume; Enter appears dead, messages silently dropped
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 22
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
问题类别 · Category
对话 / Agent 交互 · Agent chat (session resume)
涉及框架 · Framework
ZCode Agent(自研)
严重程度 · Severity / 复现频率 · Reproducibility
阻塞使用 · Blocking / 必现 · Always
版本 · Version / 环境 · Environment
3.7.3 (Linux AppImage) / custom OpenAI-compatible provider configured with an API key
问题描述 · Description
After quitting and relaunching ZCode, pre-existing conversations in certain workspaces cannot send messages: typing works, pressing Enter produces no visible result. Starting a new conversation works fine. The message is admitted then cancelled server-side with status_reason='restoreWarning' (protocol error -32031, code ZCODE_RUNTIME_MODEL_UNAVAILABLE), and no error is surfaced in the UI.
Notably, sessions in a workspace whose path retains a trailing slash (e.g. /path/to/project/) fail on every resume, at any time after launch — even minutes after the provider registry has synced. Sessions in a workspace without a trailing slash (e.g. the default conversation workspace) always work. The failure is deterministic per workspace.
复现步骤 · Steps to reproduce
- Have a project workspace whose path is seen by the agent with a trailing slash (e.g.
/path/to/project/). - Create a conversation there, exchange messages, then quit ZCode completely.
- Relaunch ZCode and open that conversation. Type a message and press Enter — nothing visibly happens.
- Wait any amount of time (even after the model list is fully populated) and try again — still rejected.
- A conversation in a workspace without the trailing slash (e.g. the default conversation workspace) sends fine immediately.
期望表现 · Expected behavior
A resumed session should accept messages as soon as the app is usable, exactly like a new conversation.
实际表现 · Actual behavior
Sends are rejected with -32031 while the restoreWarning guard is armed; the input ledger records status='cancelled', status_reason='restoreWarning' and the message is silently dropped (never posted, no UI feedback), so the session appears permanently broken.
根因 · Root cause (verified against the 3.7.3 bundle and runtime logs)
The agent runtime keys its workspace model catalog by the workspace key from the provider-registry path, which retains the trailing slash (/path/to/project/), while sessions carry a normalized workspace key without it (/path/to/project). The model-availability check H5 (bootstrap.zcode_protocol) performs an exact-key lookup (workspaceModelCatalogs.get(workspaceKey)), so for such workspaces it always misses:
- Every resume then arms
restoreWarning(typeZCODE_RUNTIME_MODEL_UNAVAILABLE, message "历史任务使用的模型已不可用…") and uses the deferred model adapter. - While armed,
session/send,sendTextandcompactthrow-32031; the input is cancelled in the ledger and dropped. - The clearing paths fail for these sessions: the provider-registry-arrival handler runs before the resume arms the warning (so it never clears it), and the
workspace/readStateclear path is gated on the app's current model matching the incoming runtime model — which the deferred adapter cannot satisfy — so it returns early without clearing. - A secondary race affects all workspaces on cold start: resumes issued before the provider-registry sync completes arm the warning for the first seconds after launch.
Runtime evidence (sanitized): zcode_protocol.session_resume.deferred_model_adapter … reason: "runtime_model_unavailable" — observed on resumes that happened after the catalog was already populated, with the session workspace key and the registry workspace key differing only by the trailing slash.
建议修复 · Proposed fix
Primary: normalize workspace keys — a single canonical form for catalog keys, session workspace records, and lookups (or make H5/catalog lookups tolerant of trailing-slash differences). This alone fixes the deterministic per-workspace failure.
Defense in depth:
- Include the already-resolved runtime model in
session/resume(the host already sends it inworkspace/readState), so the guard cannot arm on the cold-start race. - Surface the
-32031/restoreWarningrejection in the composer instead of silently cancelling the input.
Possibly related: #173.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating H5 in bootstrap.zcode_protocol and trace workspace keys from the provider-registry catalog through session resume and workspace/readState. Verify how trailing-slash normalization affects the restoreWarning guard and its clearing paths. Done means resumed sessions in trailing-slash workspaces accept sends reliably, including during cold start.
Written by the indexing model from the issue text.
Assessment
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100