{"record":{"id":"8af41e8f76de33db","repo":"paperclipai/paperclip","slug":"action-tool-mismatch","errorCode":"action_tool_mismatch","errorMessage":"Approved action request is for a different tool","messagePattern":"Approved action request is for a different tool","errorType":"http","errorClass":"ToolGatewayHttpError","httpStatus":409,"severity":"error","filePath":"server/src/services/tool-gateway.ts","lineNumber":5761,"sourceCode":"        invocationId: invocation.id,\n        toolName: invocation.toolName,\n        ownsExecutingClaim: true,\n      });\n    }\n\n    const argumentsSummary = validateToolContent({\n      value: parameters,\n      direction: \"arguments\",\n      sensitiveMode: \"redact\",\n      promptInjectionMode: \"ignore\",\n    }).summary;\n    // Final recheck at the last DB write before dispatch: tool and snapshot\n    // resolution above involve network calls, so re-verify the issue is still\n    // open now that only the provider call remains. A close that commits after\n    // 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\"","sourceCodeStart":5743,"sourceCodeEnd":5779,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/tool-gateway.ts#L5743-L5779","documentation":"Replay consistency guard: the tool name on the stored invocation does not equal the tool the session is currently calling. The 409 action_tool_mismatch prevents replaying an approval granted for one tool against a different tool within the same session context.","triggerScenarios":"Thrown at server/src/services/tool-gateway.ts:5576 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Execute the approved action with the same tool it was approved for; tool substitution invalidates the approval."],"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"}