{"record":{"id":"f003c0fe432b379b","repo":"paperclipai/paperclip","slug":"signed-arguments-invalid","errorCode":"signed_arguments_invalid","errorMessage":"Approved tool action arguments signature is invalid","messagePattern":"Approved tool action arguments signature is invalid","errorType":"http","errorClass":"ToolGatewayHttpError","httpStatus":409,"severity":"error","filePath":"server/src/services/tool-gateway.ts","lineNumber":5858,"sourceCode":"      });\n      throw error;\n    }\n  }\n\n  async function matchingAgentActionRequest(input: {\n    session: ToolGatewaySession;\n    toolName: string;\n    argumentsHash: string;\n  }) {\n    if (!input.session.issueId || !input.session.agentId) return null;\n    const [match] = await db\n      .select({ actionRequest: toolActionRequests, invocation: toolInvocations })\n      .from(toolActionRequests)\n      .innerJoin(toolInvocations, eq(toolInvocations.id, toolActionRequests.invocationId))\n      .where(and(\n        eq(toolActionRequests.companyId, input.session.companyId),\n        eq(toolActionRequests.issueId, input.session.issueId),\n        eq(toolActionRequests.canonicalArgumentsHash, input.argumentsHash),\n        eq(toolInvocations.agentId, input.session.agentId),\n        eq(toolInvocations.toolName, input.toolName),\n        inArray(toolActionRequests.status, [\"pending\", \"approved\", \"executing\", \"rejected\", \"executed\"]),\n      ))\n      .orderBy(desc(toolActionRequests.createdAt))\n      .limit(1);\n    if (!match) return null;\n    // The gateway builds an ask-first request in two steps inside one call: it\n    // inserts the row with a null signature and a null expiry, then signs the\n    // row and sets the expiry. A concurrent matching call can observe the row in\n    // this window. A null signature does not prove the create stopped, because a\n    // parallel create can still be signing the same row right now. Only treat an\n    // unsigned row as abandoned after the grace time from createdAt has passed;\n    // before that, return the match so the retry replays approval_required and\n    // does not create a duplicate request or expire a live row. After the grace\n    // time an unsigned row stays pending forever and the review queue hides it,\n    // so it can never be approved. Do not replay it as a live approval. Expire\n    // the row and let the retry create a fresh, signable request. A null expiry","sourceCodeStart":5840,"sourceCodeEnd":5876,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/tool-gateway.ts#L5840-L5876","documentation":"Integrity failure replaying an approved action: readSignedToolArgumentsPayload could not verify the signed arguments against the stored invocation (bad signature, wrong secret, or corrupt payload). The 409 blocks execution because the reviewed arguments cannot be proven authentic since the approval was signed.","triggerScenarios":"Thrown at server/src/services/tool-gateway.ts:5671 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["The signed arguments blob is invalid or tampered. Do not modify approved payloads; request a new signed 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"}