deepseek-ai/deepseek-harness · error · SessionCreateError
session create failed: ${rpcError.code}: ${rpcError.message}
Error message
session create failed: ${rpcError.code}: ${rpcError.message} What it means
sessions.create() forwards the create request over RPC and the host answered with a failed result; the client wraps the RpcError (code and message) in a SessionCreateError that also carries the requested sessionId when one was preallocated. Reaching this error means a host-side rejection came back as a Result, not a transport throw — the embedded code says why (unknown workspace, inaccessible cwd, duplicate id, host refusal). On success the same path refreshes the project list, so a failed create also means that refresh did not happen.
Source
Thrown at packages/client/runtime/src/client/sessions/service.ts:487
/** Drop generation-scoped live interaction state the moment a connection generation dies. */
handleDisconnected(): void {
this.manager.handleDisconnected()
}
/**
* Create a session on the host. Resolution guarantee: by the time the
* promise resolves, the created session is in the list store and
* {@link SessionRuntime.binding} resolves it — callers (New Session
* draft hand-off) may address the scope synchronously, without waiting a
* notifier flush. The synchronous projection below makes this structural
* rather than an accident of microtask ordering.
* @param opts - target workspace or directory and an optional preallocated id.
* @returns the new session id.
* @throws {SessionCreateError} with the requested id.
*/
async create(opts: { workspaceId?: WorkspaceId; cwd?: string; sessionId?: SessionId } = {}): Promise<SessionId> {
const result = await this.manager.create(opts)
if (!result.ok) throw new SessionCreateError(result.error, opts.sessionId)
this.projectList()
return result.value.sessionId
}
/**
* Fork a session from a completed-turn prefix of the source (same
* synchronous-addressability guarantee as {@link SessionRuntime.create}:
* on resolution the child is in the list store and open() can target it).
* @param opts - source session id, the optional event seq anchoring the
* cut (the boundary is the first turn/end at or after it; an in-log
* anchor in an open turn is unavailable rather than clipped backward),
* and whether to increment an inherited durable title before resolving.
* A fractional anchor floors to a real event seq: the frozen nodes of an
* interrupted turn carry flow-ordering seqs between two events, and the
* wire takes integers only.
* @returns the child session id.
* @throws {SessionForkError} with the source id.
* @throws {Error} when a requested child-title rename fails after creation.View on GitHub (pinned to b150a551b8)
Solutions
- Read the embedded RpcError code and message off the SessionCreateError to classify the refusal before acting
- Refresh the workspace/project list and pass a workspaceId taken from that fresh list
- Drop or re-mint the preallocated sessionId when the code indicates an id collision
- Verify the cwd exists host-side and the connection is healthy, then retry once at most
Example fix
// before
const id = await sessions.create({ workspaceId, sessionId })
// after — classify the host refusal instead of losing it
try {
const id = await sessions.create({ workspaceId, sessionId })
} catch (error) {
if (error instanceof SessionCreateError) {
// error.message reads 'session create failed: <code>: <message>'; the requested id travels on the error
throw new Error(`cannot create session in workspace ${workspaceId}: ${error.message}`)
}
throw error
} Defensive patterns
Strategy: try-catch
Try / catch
try {
return await sessions.create(opts)
} catch (error) {
if (error instanceof SessionCreateError) {
// inspect the embedded '<code>: <message>' text and the carried requested id;
// retry once only for transient classes, with a fresh preallocated id
}
throw error
} Prevention
- Take workspaceId from a freshly listed workspace set, never from persisted UI state
- Mint a new sessionId per create attempt instead of reusing one after failures
- Verify the cwd exists on the host before sending it
- Log the embedded RpcError code — it distinguishes workspace, cwd, and id-collision refusals
When it happens
Trigger: await sessions.create({ workspaceId, cwd, sessionId }) with a workspaceId absent from the host's current workspace set, a cwd the host cannot access, a sessionId that already exists host-side, or any other host refusal returned as a failed Result from manager.create().
Common situations: Using a workspace id captured before the host's workspace list changed; passing a local path that does not exist host-side; retrying a create with the same preallocated id after an earlier partial attempt; host permission or policy changes between listing and creating.
Related errors
- session fork failed: ${rpcError.code}: ${rpcError.message}
- context-not-found
- transport failure for ${channel}/${endpoint}: HTTP ${respons
- rpcId mismatch for ${endpoint}: sent ${rpcId}, got ${full.rp
- fork child rename failed: ${renamed.error.code}: ${renamed.e
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/ef2b0e44c91144cd.
Report an issue: GitHub.