paperclipai/paperclip · error
OpenCode thread is not open
Error message
OpenCode thread is not open
What it means
The OpenCode app-server proxy translates JSON-RPC requests (runnerd protocol) into calls against an OpenCode driver session. 'turn/start' requires an open thread/session; the proxy throws this error when a turn is requested before 'thread/start' or 'thread/resume' succeeded (or after the session was never opened in this process).
Source
Thrown at packages/paperclip-runner/src/cli/opencode-app-server-proxy.ts:347
let result: unknown;
switch (message.method) {
case "initialize":
result = {
user: { sessionId: "opencode" },
serverInfo: { name: "opencode", version: "1.18.29" },
};
break;
case "thread/start":
result = await open(params, false);
break;
case "thread/resume":
result = await open(params, true);
break;
case "collaborationMode/list":
result = openCodeProxyCollaborationModes(activeModel);
break;
case "turn/start": {
if (!session) throw new Error("OpenCode thread is not open");
assertOpenCodeProxyCollaborationMode(params);
const inputItems = Array.isArray(params.input)
? params.input.map(record)
: [];
const messageText = inputItems
.map((entry) => text(entry.text))
.filter(Boolean)
.join("\n");
const turn = await session.startTurn({
message: { role: "user", text: messageText },
});
activeTurnId = turn.turnId;
// OpenCode normally publishes session/turn startup over SSE, but a fast
// completion can make the synchronous prompt response the only place the
// authoritative turn id is observed. Emit the normalized notification
// after this request's JSON-RPC response when SSE did not already announce
// it. runnerd buffers notifications received while awaiting a response,
// so replaying an earlier SSE announcement would violate strict turnView on GitHub (pinned to 01ad858492)
Solutions
- Send 'thread/start' (or 'thread/resume' with the existing thread id) before any 'turn/start'.
- Check proxy stderr for bootstrap failures (missing/misconfigured opencode CLI) that prevented the session from opening.
- Retry thread creation first, then re-issue the turn request.
- If resuming an existing conversation, use 'thread/resume' with the prior driver session id instead of assuming state persists.
Example fix
// before
await rpc({ method: 'turn/start', params: { input: [{ text: 'hi' }] } });
// after
await rpc({ method: 'thread/start', params: { cwd } });
await rpc({ method: 'turn/start', params: { input: [{ text: 'hi' }] } }); Defensive patterns
Strategy: try-catch
Validate before calling
let threadOpen = false;
async function ensureThread(params) {
if (!threadOpen) {
await rpc({ method: 'thread/start', params });
threadOpen = true;
}
} Try / catch
try {
await rpc({ method: 'turn/start', params });
} catch (e) {
if (e.message.includes('thread is not open')) {
await rpc({ method: 'thread/start', params: threadParams });
await rpc({ method: 'turn/start', params });
} else throw e;
} Prevention
- Always run the initialize + thread/start handshake before issuing turn commands.
- Track session-open state in the client and re-open after any proxy restart.
- Monitor proxy stderr for bootstrap failures instead of blindly retrying turns.
When it happens
Trigger: Sending a JSON-RPC 'turn/start' request to the proxy without first sending 'thread/start' or 'thread/resume', or after a prior 'thread/start' failed and left `session` null.
Common situations: Client reconnects and skips the initialize/thread handshake; a bootstrap failure (e.g. missing opencode binary) means the thread never opened but the client retries turns; test harness drives turn/start directly.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- OpenCode interruption is unavailable
- opencode_run_attach_busy
- session_unavailable
- OpenCode target executable is not a regular file
- native_session_attach_binding_mismatch
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/1ce4f9ec1b4f64de.
Report an issue: GitHub.