{"record":{"id":"415115a9d29311c1","repo":"paperclipai/paperclip","slug":"opencode-resumed-a-different-session","errorCode":null,"errorMessage":"OpenCode resumed a different session","messagePattern":"OpenCode resumed a different session","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts","lineNumber":314,"sourceCode":"          cwd,\n          trace,\n          dispatch: (call) => {\n            if (session === null)\n              throw new Error(\"OpenCode session is not ready for tool calls\");\n            return session.dispatchTool(call);\n          },\n        });\n        const fetcher = this.#options.fetch ?? globalThis.fetch;\n        let providerSessionId =\n          snapshot?.providerSessionId ?? snapshot?.driverSessionId ?? null;\n        if (providerSessionId !== null) {\n          const existing = await api(\n            fetcher,\n            runtime,\n            `/session/${encodeURIComponent(providerSessionId)}`,\n          );\n          if (!isRecord(existing) || text(existing.id) !== providerSessionId)\n            throw new Error(\"OpenCode resumed a different session\");\n        } else {\n          const created = await api(fetcher, runtime, \"/session\", {\n            method: \"POST\",\n            body: JSON.stringify({ title: `Paperclip ${input.runId}` }),\n          });\n          providerSessionId = text(record(created).id);\n          if (!providerSessionId)\n            throw new Error(\"OpenCode session creation omitted its id\");\n        }\n        session = new OpenCodeHarnessSession({\n          runtime,\n          fetcher,\n          runId: input.runId,\n          normalizedSessionId: input.normalizedSessionId,\n          providerSessionId,\n          workingDirectory: cwd,\n          runnerInstanceId:\n            this.#options.runnerInstanceId ??","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts#L296-L332","documentation":"When resuming, the driver fetches the existing provider session by id and verifies the returned record's id matches the requested providerSessionId. It throws this error if the OpenCode server returns a record whose id differs (or a non-record), meaning the server would resume a different conversation than the one stored.","triggerScenarios":"GET /session/<providerSessionId> returns a session object with a different id — typically after the server restarted with a new session store, session id collision/normalization mismatch, or a proxy returning a default/first session.","commonSituations":"OpenCode server restarted losing session state, providerSessionId persisted from an older server instance, session ids with encodings mangled by encodeURIComponent on one side, load balancer routing to another instance.","solutions":["Verify the OpenCode server still has the session (GET /session/<id>) and that its id matches exactly.","If the server lost the session, create a new session instead of resuming (clear the stale providerSessionId).","Point all requests at the same OpenCode server instance (sticky routing / single instance).","Log the returned existing.id and requested id to spot normalization or encoding differences and fix the persistence layer."],"exampleFix":"// before\nconst existing = await api(fetcher, runtime, `/session/${providerSessionId}`); // mismatched id returned, throws\n// after\nconst existing = await api(fetcher, runtime, `/session/${encodeURIComponent(providerSessionId)}`);\nif (!isRecord(existing) || text(existing.id) !== providerSessionId) {\n  providerSessionId = text(record(await api(fetcher, runtime, '/session', { method: 'POST', body: JSON.stringify({ title: `Paperclip ${input.runId}` }) })).id);\n}","handlingStrategy":"fallback","validationCode":"const existing = await api(fetcher, runtime, `/session/${encodeURIComponent(providerSessionId)}`);\nconst matches = isRecord(existing) && text(existing.id) === providerSessionId;\nif (!matches) console.warn(`OpenCode session ${providerSessionId} missing/mismatched; will create a new session`);","typeGuard":"const sessionMatches = (r: unknown, id: string): r is { id: string } => isRecord(r) && text((r as { id?: unknown }).id) === id;","tryCatchPattern":"try { await resumeOrOpen(providerSessionId); } catch (e) { if ((e as Error).message === 'OpenCode resumed a different session') { await clearStoredProviderSessionId(); await openSession(input); } else throw e; }","preventionTips":["Persist providerSessionId only with the server instance that issued it","Pin runs to a single OpenCode server (no cross-instance round-robin)","Clear stored session ids when the OpenCode server restarts","Always encodeURIComponent the session id in the path"],"tags":["opencode","session","resume","http"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}