[BUG] Read: `pages: ""` on a non-PDF file fails validation, and PreToolUse hooks can't work around it (still on 2.1.286)
What's wrong
Read rejects a call to a non-PDF file when the optional pages argument is an empty string, instead of treating it as unset:
<tool_use_error>Invalid pages parameter: "". Use formats like "1-5", "3", or "10-20". Pages are 1-indexed.</tool_use_error>
Models that fill every optional field send pages: "" on almost every Read. Each such read fails and gets retried, so it costs an extra tool call. In our headless agent fleet it accounts for most tool errors on file-reading runs. #70734 shows the same thing from Opus 4.7/4.8.
This was reported in #56749 and #70734. Both were auto-closed as stale rather than fixed. It still reproduces on 2.1.286 (the latest release).
PreToolUse hooks can't work around it
We tried to normalise the input with a PreToolUse hook on Read (hookSpecificOutput.updatedInput with pages removed). The hook never runs for this call: input validation happens before PreToolUse hooks. A logging hook on Read fired 0 times for the pages: "" call and fired normally for a valid Read. So an operator has no way to repair the call before it fails.
Reproduce (2.1.286, headless)
echo hello > a.md
claude -p 'Call the Read tool once with file_path "'"$PWD"'/a.md" and pages set to the empty string "". Do not retry.' \
--model haiku --permission-mode dontAsk --allowedTools Read --output-format stream-json --verbose < /dev/null
# tool_use input: {"file_path": ".../a.md", "pages": ""}
# tool_result: Invalid pages parameter: "". ...
Add a PreToolUse hook with matcher Read that appends its stdin to a file. It is never called for this request.
Expected
- A blank or whitespace-only
pagesis treated as unset, the same as omitting it. - For non-PDF files,
pagesis ignored, which is already what happens for a non-empty value:pages: "1"on a 300-line.mdreturns the whole file.
Environment
- Claude Code 2.1.286, macOS and Linux (headless
claude -p) - Models: Haiku 4.5 when told to send
""; Opus 4.7/4.8 send it on their own per #70734
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗