{"record":{"id":"527249fa9c08df95","repo":"paperclipai/paperclip","slug":"action-expired","errorCode":"action_expired","errorMessage":"Tool action request approval has expired","messagePattern":"Tool action request approval has expired","errorType":"http","errorClass":"ToolGatewayHttpError","httpStatus":409,"severity":"error","filePath":"server/src/services/tool-gateway.ts","lineNumber":5776,"sourceCode":"    // this read has raced an execution that was approved, claimed, and verified\n    // while the issue was open; that instant is irreducible for an external\n    // side effect gated by DB state (holding a DB lock across a remote provider\n    // call is not an option), and the accepted linearization is that the\n    // execution wins — its result still lands on the expired card via\n    // reflectToolActionInteractionLifecycle.\n    await assertIssueOpenForApprovedAction({ claimed, invocation });\n\n    const startedAt = Date.now();\n    await db\n      .update(toolInvocations)\n      .set({ status: \"executing\", approvalState: \"approved\", startedAt: new Date(), updatedAt: new Date() })\n      .where(eq(toolInvocations.id, invocation.id));\n    await reflectToolActionInteractionLifecycle({ actionRequestId: claimed.id, status: \"executing\" });\n\n    try {\n      const executionTimeoutMs = timeoutMs(APPROVED_EXECUTION_TIMEOUT_MS);\n      const result = tool.providerType === \"mcp_remote_http\"\n        ? (await executeRemoteHttpTool(session, tool, parameters, executionTimeoutMs, invocation.id)).result\n        : tool.providerType === \"mcp_local_stdio\"\n          ? (await executeLocalStdioTool(session, tool, parameters, executionTimeoutMs)).result\n          : tool.providerType !== \"paperclip_plugin\"\n            ? await runWithTimeout(executeBuiltinTool(session, tool, parameters), executionTimeoutMs)\n            : (() => { throw new ToolGatewayHttpError(409, \"Plugin actions cannot execute outside their originating run\", \"approved_execution_unsupported\"); })();\n      const resultRecord = asRecord(result);\n      if (resultRecord?.error) throw new ToolGatewayHttpError(502, String(resultRecord.content || resultRecord.error), \"tool_execution_failed\");\n      const resultValidation = validateToolContent({\n        value: result,\n        direction: \"result\",\n        sensitiveMode: \"redact\",\n        promptInjectionMode: \"block\",\n      });\n      const now = new Date();\n      await db.update(toolInvocations).set({\n        status: \"succeeded\",\n        resultHash: resultValidation.summary.sha256 ?? null,\n        resultSummary: resultValidation.summary,","sourceCodeStart":5758,"sourceCodeEnd":5794,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/tool-gateway.ts#L5758-L5794","documentation":"Expiry sweep during approved-action replay: actionRequest.expiresAt has passed, so the request is transitioned to expired with resolvedAt stamped before the 403/409 is returned. The approval is no longer valid; the agent must request a fresh approval if the action is still needed.","triggerScenarios":"Thrown at server/src/services/tool-gateway.ts:5591 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["The approval expired. Request a fresh approval and execute within its validity window."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}