{"record":{"id":"436347ea0b63f349","repo":"paperclipai/paperclip","slug":"paperclip-runner-chat-attachment-read-arguments-invalid","errorCode":"paperclip_runner_chat_attachment_read_arguments_invalid","errorMessage":"paperclip_runner_chat_attachment_read_arguments_invalid","messagePattern":"paperclip_runner_chat_attachment_read_arguments_invalid","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/native-runtime/chat-attachment-read.ts","lineNumber":77,"sourceCode":"      storageTimeoutMs?: number;\n    },\n  ) {}\n\n  #assertOpen() {\n    if (this.#closed)\n      throw new Error(\"paperclip_runner_chat_attachment_read_scope_closed\");\n  }\n\n  read(input: { sourceCommentId: string; attachmentId: string }) {\n    this.#assertOpen();\n    if (\n      !UUID.test(input.sourceCommentId) ||\n      !UUID.test(input.attachmentId) ||\n      Object.keys(input).some(\n        (key) => key !== \"sourceCommentId\" && key !== \"attachmentId\",\n      )\n    ) {\n      throw new Error(\n        \"paperclip_runner_chat_attachment_read_arguments_invalid\",\n      );\n    }\n    if (this.options.executionTargetKind !== \"local\") {\n      throw new Error(\n        \"paperclip_runner_chat_attachment_remote_staging_unsupported\",\n      );\n    }\n    if (++this.#readCount > 20)\n      throw new Error(\"paperclip_runner_chat_attachment_read_limit\");\n    const pending = this.#read(input);\n    this.#pending.add(pending);\n    void pending\n      .finally(() => this.#pending.delete(pending))\n      .catch(() => undefined);\n    return pending;\n  }\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/native-runtime/chat-attachment-read.ts#L59-L95","documentation":"read() validates its input strictly before doing any work: both sourceCommentId and attachmentId must be UUID-shaped strings, and the input object may contain no extra keys (additionalProperties false). Any violation throws this error synchronously. It is a pre-flight guard for the read_chat_attachment tool contract.","triggerScenarios":"Calling read() with a non-UUID or empty sourceCommentId/attachmentId; passing extra properties in the input object (e.g. a guessed 'path' or 'commentId' key); passing null/undefined/numeric ids; a model emitting malformed tool arguments.","commonSituations":"An LLM hallucinating tool arguments that don't match the JSON schema; hand-rolled tool calls using display ids instead of the UUIDs returned by list_chat_attachments; adding a new input field without updating the schema.","solutions":["Obtain both ids verbatim from the list_chat_attachments tool output; never construct them by hand.","Validate UUID format before calling read().","Strip any extra keys from the input object; only sourceCommentId and attachmentId are accepted.","If a new parameter is needed, update READ_CHAT_ATTACHMENT_TOOL_DEFINITION's inputSchema and this check together."],"exampleFix":"// before\nawait scope.read({ sourceCommentId: \"42\", attachmentId: id, path: \"./file\" });\n// after\nawait scope.read({ sourceCommentId: \"9f0c...-uuid\", attachmentId: \"2ab1...-uuid\" });","handlingStrategy":"validation","validationCode":"const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\nfunction canRead(input) {\n  return input != null\n    && UUID.test(String(input.sourceCommentId))\n    && UUID.test(String(input.attachmentId))\n    && Object.keys(input).every(k => k === \"sourceCommentId\" || k === \"attachmentId\");\n}","typeGuard":"function isValidReadInput(input: unknown): input is { sourceCommentId: string; attachmentId: string } {\n  const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n  if (typeof input !== \"object\" || input === null) return false;\n  const o = input as Record<string, unknown>;\n  return typeof o.sourceCommentId === \"string\" && UUID.test(o.sourceCommentId)\n    && typeof o.attachmentId === \"string\" && UUID.test(o.attachmentId)\n    && Object.keys(o).length === 2;\n}","tryCatchPattern":"try {\n  const file = await scope.read(input);\n} catch (e) {\n  if (e.message === \"paperclip_runner_chat_attachment_read_arguments_invalid\") return { status: \"bad_tool_arguments\" };\n  throw e;\n}","preventionTips":["Copy ids verbatim from list_chat_attachments output.","Validate tool arguments against the JSON schema before dispatching.","Never add fields to the tool input without updating the schema and validator together.","Sanitize model-generated tool calls with a strict parser."],"tags":["validation","uuid","tool-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-23T08:17:48.524Z"}