{"record":{"id":"a9961e963f549ba2","repo":"vercel/ai","slug":"recovered-acp-session-is-disposed","errorCode":null,"errorMessage":"Recovered ACP session is disposed.","messagePattern":"Recovered ACP session is disposed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/harness-acp/src/v1/bridge/recovered-session.ts","lineNumber":58,"sourceCode":"  sessionId,\n  restorationResponse,\n  updates,\n}: {\n  agent: acp.ClientContext;\n  sessionId: string;\n  restorationResponse: acp.ResumeSessionResponse | acp.LoadSessionResponse;\n  updates: ReturnType<typeof createACPRecoveredSessionUpdates>;\n}): ACPActiveSession {\n  let disposed = false;\n  return {\n    sessionId,\n    newSessionResponse: {\n      sessionId,\n      ...restorationResponse,\n    },\n    prompt: async prompt => {\n      if (disposed) {\n        throw new Error('Recovered ACP session is disposed.');\n      }\n      updates.clearErrors();\n      const response = agent.request<acp.PromptResponse, acp.PromptRequest>(\n        acp.methods.agent.session.prompt,\n        { sessionId, prompt },\n      );\n      void response.then(\n        value => {\n          updates.enqueue({\n            kind: 'stop',\n            response: value,\n            stopReason: value.stopReason,\n          });\n        },\n        error => updates.reject(error),\n      );\n      return response;\n    },","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/harness-acp/src/v1/bridge/recovered-session.ts#L40-L76","documentation":"createACPRecoveredSession's prompt() refuses to send prompts once the recovered session has been disposed (disposed flag set). The library throws this guard error because the underlying ACP session id is no longer usable after disposal.","triggerScenarios":"Calling prompt() on a recovered ACP session after dispose() was called — e.g. prompting after the bridge shut the session down, after a lifecycle teardown, or holding a stale session reference across a restart.","commonSituations":"Application code caching the session object and reusing it after an error path disposed it; concurrent shutdown racing an in-flight prompt attempt; retry logic replaying a prompt on a disposed session.","solutions":["Re-acquire the session via ensureSession (which restores/recreates it) instead of prompting the disposed instance.","Track disposal (or listen for dispose) and stop issuing prompts on the old reference.","Restructure retry logic so retries go through session re-resolution, not the stale session object."],"exampleFix":"// before\nawait cachedSession.prompt({ prompt: 'hi' }); // may be disposed\n// after\nconst session = await ensureSession(); // returns a live/recovered session\nawait session.prompt({ prompt: 'hi' });","handlingStrategy":"try-catch","validationCode":"if (session.isDisposed?.()) throw new Error('Refusing to prompt: session already disposed');\n// or track disposal yourself:\nlet disposed = false;\nsession.addEventListener?.('dispose', () => { disposed = true; });","typeGuard":null,"tryCatchPattern":"try {\n  await session.prompt({ prompt });\n} catch (error) {\n  if (error instanceof Error && error.message === 'Recovered ACP session is disposed.') {\n    const fresh = await ensureSession();\n    return fresh.prompt({ prompt });\n  }\n  throw error;\n}","preventionTips":["Never cache recovered-session objects across lifecycle boundaries; re-resolve via ensureSession.","Cancel pending prompts during shutdown.","Guard concurrent dispose/prompt races with a single owner of the session lifecycle."],"tags":["acp","session","lifecycle"],"backgroundTag":"session-disposed","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}