{"record":{"id":"c12cf0b824273318","repo":"Mintplex-Labs/anything-llm","slug":"this-agent-invocation-is-already-closed","errorCode":null,"errorMessage":"This agent invocation is already closed","messagePattern":"This agent invocation is already closed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"server/utils/agents/index.js","lineNumber":544,"sourceCode":"      },\n      { user, thread }\n    );\n\n    this.provider = router.resolvedRoute.provider;\n    this.model = router.resolvedRoute.model;\n    this.routingMetadata = router.routingMetadata;\n    // Held so the model-router-cooldown plugin can restart the cooldown when\n    // the agent stops responding. Routing re-resolves per turn, so this always\n    // points at the router for the current route.\n    this._modelRouter = router;\n  }\n\n  async #validInvocation() {\n    const invocation = await WorkspaceAgentInvocation.getWithWorkspace({\n      uuid: String(this.#invocationUUID),\n    });\n    if (invocation?.closed)\n      throw new Error(\"This agent invocation is already closed\");\n    this.invocation = invocation ?? null;\n  }\n\n  parseCallOptions(args, config = {}, pluginName) {\n    const callOpts = {};\n    for (const [param, definition] of Object.entries(config)) {\n      if (\n        definition.required &&\n        (!Object.prototype.hasOwnProperty.call(args, param) ||\n          args[param] === null)\n      ) {\n        this.log(\n          `'${param}' required parameter for '${pluginName}' plugin is missing. Plugin may not function or crash agent.`\n        );\n        continue;\n      }\n      callOpts[param] = Object.prototype.hasOwnProperty.call(args, param)\n        ? args[param]","sourceCodeStart":526,"sourceCodeEnd":562,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/utils/agents/index.js#L526-L562","documentation":"Thrown by #validInvocation() (server/utils/agents/index.js:539) during agent.init() when the WorkspaceAgentInvocation record for the invocation UUID has closed === true. The guard prevents starting an agent session against an invocation that was already ended (closed by the user, timed out, or previously completed).","triggerScenarios":"agent.init() is called for an invocation UUID whose DB row is closed - e.g. a replayed request, a duplicate webhook, a UI that re-triggers a finished agent thread, or an invocation closed between dispatch and init().","commonSituations":"User closed the agent chat and an in-flight request retried; background job replayed; concurrent duplicate submissions; invocation closed by another tab.","solutions":["Have the client open a new agent invocation instead of reusing the closed UUID.","If unexpected, inspect why the row is closed (WorkspaceAgentInvocation.closed) and ensure no code path closes it prematurely.","Add idempotency: ignore re-init on closed invocations rather than throwing."],"exampleFix":"// before\nconst agent = new AgentHandler({ uuid });\nawait agent.init();\n// after\nconst inv = await WorkspaceAgentInvocation.getWithWorkspace({ uuid });\nif (inv?.closed) return startNewInvocation();\nconst agent = new AgentHandler({ uuid });\nawait agent.init();","handlingStrategy":"validation","validationCode":"const inv = await WorkspaceAgentInvocation.getWithWorkspace({ uuid: String(uuid) });\nif (inv?.closed) return openFreshInvocation();","typeGuard":null,"tryCatchPattern":"try { await agent.init(); } catch (e) { if (/already closed/.test(e.message)) return startNewAgentSession(); throw e; }","preventionTips":["Check invocation.closed before calling init.","Have the client create a new invocation when reopening an agent chat.","Guard duplicate/replayed requests with idempotency keys."],"tags":["agents","invocation","lifecycle","concurrency"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}