{"record":{"id":"f27562393e9202a4","repo":"rtk-ai/rtk","slug":"hook-stdin-exceeds-byte-limit","errorCode":null,"errorMessage":"hook stdin exceeds {} byte limit","messagePattern":"hook stdin exceeds (.+?) byte limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/hooks/hook_cmd.rs","lineNumber":23,"sourceCode":"\nuse super::constants::PRE_TOOL_USE_KEY;\nuse super::permissions::{self, PermissionVerdict};\nuse anyhow::{Context, Result};\nuse serde_json::{json, Value};\nuse std::io::{self, Read, Write};\n\nuse crate::discover::registry::{has_heredoc, rewrite_command};\n\nconst STDIN_CAP: usize = 1_048_576; // 1 MiB\n\nfn read_stdin_limited() -> Result<String> {\n    let mut input = String::new();\n    io::stdin()\n        .take((STDIN_CAP + 1) as u64)\n        .read_to_string(&mut input)\n        .context(\"Failed to read stdin\")?;\n    if input.len() > STDIN_CAP {\n        anyhow::bail!(\"hook stdin exceeds {} byte limit\", STDIN_CAP);\n    }\n    Ok(input)\n}\n\n// ── Copilot hook (VS Code + Copilot CLI) ──────────────────────\n\n/// Format detected from the preToolUse JSON input.\nenum HookFormat {\n    /// VS Code Copilot Chat / Claude Code: `tool_name` + `tool_input.command`, supports `updatedInput`.\n    /// If using the PreToolUse pascal case form, Copilot CLI also remaps its native `bash`/`powershell`\n    /// runtime tool to `tool_name: \"Bash\"` for this schema and honors its `updatedInput`, live-verified\n    /// on Linux+Windows 11 with Copilot CLI 1.0.73+ by rewriting a marker command end-to-end\n    /// see <https://github.com/rtk-ai/rtk/pull/3179#issuecomment-5088268495>.\n    VsCode { command: String },\n    /// GitHub Copilot CLI's native schema: camelCase `toolName` + `toolArgs` (JSON string),\n    /// supports `modifiedArgs` for transparent rewrite. `rtk init --copilot` no longer\n    /// registers this schema (Copilot CLI honors the PascalCase `VsCode` schema on its\n    /// own — registering both caused a redundant second hook invocation per tool call,","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/rtk-ai/rtk/blob/d977e1c31621fe8704e6500ceeb9c7a0de2b6836/src/hooks/hook_cmd.rs#L5-L41","documentation":"RTK's PreToolUse hook (Claude Code / VS Code Copilot CLI) reads the tool-call JSON from stdin through read_stdin_limited, capped at STDIN_CAP = 1 MiB. The reader takes CAP+1 bytes so oversize input is rejected outright (bail!) instead of truncated — a truncated hook JSON would be unparseable and could silently disable filtering.","triggerScenarios":"An agent tool call whose serialized JSON exceeds 1 MiB: a bash command embedding a giant heredoc (data file pasted inline), a base64 blob (certificates, images), or minified bundle content. The hook receives the whole tool_input envelope, so the payload — not the visible command — is what crosses the cap.","commonSituations":"Agents pasting whole files as heredocs instead of using file-write tools; inline base64 of binaries/certs; generated code or fixtures injected into commands; very long curl payloads with embedded JSON.","solutions":["Move big payloads out of the command: write them with a file tool first, or fetch them (`curl -o /tmp/payload ...`), then reference the path in the command","Split the work so each tool call stays well under 1 MiB of serialized JSON","For bulky inline data, keep only an indirect reference (path, URL, or `base64 -d /tmp/x.b64`) in the command itself"],"exampleFix":"# before: heredoc pushes hook JSON past 1 MiB\ntee /tmp/app.conf <<'EOF'\n<2 MB of config...>\nEOF\n# hook stdin exceeds 1048576 byte limit\n\n# after: write the file with a file tool (no hook stdin), then just reference it\n# tool: write file /tmp/app.conf  (payload goes through the file API)\nchmod 644 /tmp/app.conf && wc -c /tmp/app.conf","handlingStrategy":"validation","validationCode":"bash:\n# keep the tool-call payload well under the 1 MiB hook cap before invoking the agent tool\nSIZE=$(wc -c < payload.json 2>/dev/null || echo 0)\nif [ \"$SIZE\" -gt 1000000 ]; then\n  echo \"payload $SIZE bytes exceeds ~1 MiB hook stdin cap — reference a path instead\" >&2\n  exit 2\nfi","typeGuard":null,"tryCatchPattern":"rust (hook harness):\nmatch read_stdin_limited() {\n    Err(e) if e.to_string().contains(\"hook stdin exceeds\") => {\n        // input too large to inspect: allow the tool call unfiltered rather than block it\n        Ok(std::process::exit(0))\n    }\n    r => r,\n}","preventionTips":["Never paste multi-hundred-KB heredocs/base64 into agent bash calls — write files with file tools and reference paths","Budget the serialized tool_input JSON, not just the visible command: the hook sees the whole envelope","Keep inline payloads to kilobytes; fetch or decode bulky data from disk in the command","The 1 MiB cap (STDIN_CAP, hook_cmd.rs) is deliberate — truncation would corrupt the hook JSON"],"tags":["hooks","stdin","limits","claude-code","json","agent-tools"],"backgroundTag":null,"analyzedSha":"d977e1c31621fe8704e6500ceeb9c7a0de2b6836","analyzedAt":"2026-08-16T05:40:46.291Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}