paperclipai/paperclip · error
OpenCode event stream closed before the session became termi
Error message
OpenCode event stream closed before the session became terminal
What it means
Thrown when the SSE event stream from the OpenCode server ends (server closed the connection) while the session has not yet reached a terminal state. After up to 3 reconnect attempts the driver gives up and raises this so the caller knows the turn never completed.
Source
Thrown at packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts:1222
],
reason: "OpenCode SSE frame parsed as JSON",
});
}
} catch (error) {
if (frameId) {
this.#runtime.trace?.interpretation({
frameId,
stage: "typescript_opencode_sse_parse",
ruleId: "opencode.sse.invalid_json",
disposition: "rejected",
reason: `OpenCode SSE data was not valid JSON: ${String(error).slice(0, 400)}`,
});
}
throw error;
}
this.#mapProviderEvent(event, frameId);
}
throw new Error(
"OpenCode event stream closed before the session became terminal",
);
} catch (error) {
if (this.#closed || this.#abort.signal.aborted) return;
attempts += 1;
if (attempts > 3) {
this.#emit("harness.diagnostic", {
code: "opencode_sse_failed",
message: redact(String(error), this.#runtime.sensitiveValues),
});
this.#events.fail(error);
return;
}
await new Promise((resolve) => setTimeout(resolve, 50 * attempts));
}
}
}
View on GitHub (pinned to 01ad858492)
Solutions
- Inspect the OpenCode server logs for a crash or restart at the time of the drop and fix the underlying server failure.
- Check that reconnect/backoff (attempts up to 3) is not being exhausted by frequent drops — increase stability of the host or the server.
- If aborts were not intended, verify this.#abort is not being signaled by an upstream timeout that closes the stream.
- Retry the turn; if the session is recoverable, re-attach with the provider session id instead of starting over.
Defensive patterns
Strategy: retry
Try / catch
try {
await runTurn();
} catch (e) {
if (e instanceof Error && e.message.includes("closed before the session became terminal")) {
// inspect server logs for crash; reconnect using persisted providerSessionId and resume or re-run the turn
}
} Prevention
- Run the OpenCode server under a supervisor and monitor for crashes
- Avoid host sleep/network idle timeouts during long turns
- Persist providerSessionId so the turn can be resumed after a drop
When it happens
Trigger: The OpenCode server process exits, restarts, or drops the SSE connection while the harness session is still awaiting a terminal event (e.g. turn completion), and reconnection attempts exceed the retry limit (attempts > 3).
Common situations: OpenCode server crashes mid-turn (OOM, panic); supervisor restarts the server during a long-running turn; network idle timeout closes the connection; machine sleep/resume breaks the socket.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- OpenCode event stream returned HTTP ${response.status}
- OpenCode SSE event exceeded the retained payload limit
- dropping batch ${batch.batchId} after ${batch.attempt} attem
- Plugin worker "${pluginId}" is not running for the duplex ch
- DUPLEX_CHANNEL_OPEN_FAILED
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/b0b2c642ff026669.
Report an issue: GitHub.