{"record":{"id":"a8b7c93efad2a464","repo":"paperclipai/paperclip","slug":"paperclip-runner-tool-input-invalid","errorCode":"paperclip_runner_tool_input_invalid","errorMessage":"paperclip_runner_tool_input_invalid","messagePattern":"paperclip_runner_tool_input_invalid","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/native-runtime/paperclip-runner-tool-authority.ts","lineNumber":998,"sourceCode":"        }\n        return prepared.result;\n      },\n      {\n        onDefinitePreCommitFailure: async () => {\n          const rollback = rollbackDefinitePreCommitFailure;\n          rollbackDefinitePreCommitFailure = null;\n          await rollback?.();\n        },\n      },\n    );\n    if (publication) publishActivity(publication);\n    return result;\n  }\n\n  async #reuseChatAttachment(input: Record<string, unknown>): Promise<unknown> {\n    const idempotencyKey = requiredString(input.idempotencyKey);\n    if (idempotencyKey.length > 200) {\n      throw new Error(\"paperclip_runner_tool_input_invalid\");\n    }\n    const sourceCommentId = requiredUuid(input.sourceCommentId);\n    const attachmentId = requiredUuid(input.attachmentId);\n    const title = requiredString(input.title);\n    if (title.length > 500) throw new Error(\"paperclip_runner_tool_input_invalid\");\n    let source: ChatAttachmentReuseSource | null = null;\n    let publication:\n      Awaited<ReturnType<typeof persistActivity>>[\"publication\"] | null = null;\n    let rollbackDefinitePreCommitFailure: (() => Promise<void>) | null = null;\n    const authorize = async (tx: Db, contextSnapshot: unknown) => {\n      source = await authorizeChatAttachmentReuse({\n        db: tx,\n        binding: this.binding,\n        contextSnapshot,\n        sourceCommentId,\n        attachmentId,\n      });\n    };","sourceCodeStart":980,"sourceCodeEnd":1016,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/native-runtime/paperclip-runner-tool-authority.ts#L980-L1016","documentation":"Generic input-validation sentinel for runner tools. In #reuseChatAttachment it is thrown when the idempotencyKey exceeds 200 characters (and elsewhere when requiredString/requiredUuid checks fail). It signals the tool arguments are structurally invalid before any authorization or database work happens.","triggerScenarios":"Calling the reuse_chat_attachment tool with an idempotencyKey longer than 200 chars, or omitting/malforming idempotencyKey, sourceCommentId, attachmentId, or title so requiredString/requiredUuid throw the same sentinel.","commonSituations":"Agents embedding long UUIDs+timestamps+salts into idempotency keys, passing null/undefined arguments, or sending non-UUID strings (e.g. prefixed ids like 'comment_123') for sourceCommentId/attachmentId.","solutions":["Shorten the idempotencyKey to 200 characters or fewer (hash long composite keys, e.g. sha256 hex).","Ensure every required field is present: idempotencyKey (string), sourceCommentId (UUID), attachmentId (UUID), title (string).","Validate UUID format (RFC 4122 version 1-5, variant 89ab) before calling; strip any prefixes from ids.","Keep title at 500 characters or fewer (see error 334)."],"exampleFix":"// before\nconst key = `reuse:${issueId}:${attachmentId}:${Date.now()}-${longSalt}`; // >200 chars\n\n// after\nimport { createHash } from 'node:crypto';\nconst key = createHash('sha256').update(`reuse:${issueId}:${attachmentId}`).digest('hex');","handlingStrategy":"validation","validationCode":"const key = String(input.idempotencyKey ?? '');\nif (!key || key.length > 200) throw new Error('idempotencyKey required, max 200 chars');\nif (!input.sourceCommentId || !input.attachmentId) throw new Error('sourceCommentId and attachmentId required');","typeGuard":"const isUuid = (v: unknown): v is string =>\n  typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(v);","tryCatchPattern":null,"preventionTips":["Hash long composite keys to sha256 hex (64 chars)","Always pass string-typed non-empty values for required fields","Strip id prefixes before sending UUID-typed arguments","Pre-validate arguments with the same regex the tool uses"],"tags":["validation","input-validation","runner-tools","arguments"],"backgroundTag":"invalid-argument-value","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}