Skip to content

fix: pass prompt via stdin to avoid "Argument list too long" on large PRs#35

Merged
jbiskur merged 1 commit into
mainfrom
fix/prompt-via-stdin-arg-limit
Jun 10, 2026
Merged

fix: pass prompt via stdin to avoid "Argument list too long" on large PRs#35
jbiskur merged 1 commit into
mainfrom
fix/prompt-via-stdin-arg-limit

Conversation

@jbiskur

@jbiskur jbiskur commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Problem

run_opencode and run_gemini pass the entire prompt as a single argv argument:

opencode run -m "$full_model" "$(cat "$prompt_file")"      # line 453
gemini -y -m "$GEMINI_MODEL" --prompt "$(cat "$prompt_file")"  # line 365

On Linux the per-argument cap is MAX_ARG_STRLEN = 128 KB (PAGE_SIZE × 32). A PR with a large diff produces a 150 KB+ prompt, so the kernel rejects the exec with Argument list too long (exit 126) and validation hard-fails before the model is ever invoked.

Observed in the wild on a large PR (179 KB prompt):

/home/runner/.opencode/bin/opencode: Argument list too long
❌ OpenCode CLI failed (exit code: 126)
::error::Non-retryable error occurred.

Fix

Feed the prompt through stdin instead. A piped stream has no per-argument size limit. Verified both CLIs read a non-TTY stdin as the prompt directly from their source:

  • opencodepackages/opencode/src/cli/cmd/run.ts: const piped = process.stdin.isTTY ? undefined : await Bun.stdin.text() → used as the message when no positional arg is given.
  • geminipackages/cli/src/gemini.tsx: if (!process.stdin.isTTY) stdinData = await readStdin() → pushed as --prompt. (--prompt is also deprecated upstream, so this drops a deprecation too.)

set -o pipefail is already enabled, so $? still reflects the CLI's exit code through the | tee pipe — retry detection and exit-code handling are unchanged.

Testing

  • bash -n scripts/validate.sh — syntax clean.
  • Confirmed a 179 KB argument triggers Argument list too long at exec on Linux, while the same payload over < file stdin has no limit.
  • No behavioral change beyond prompt delivery: model, flags, output capture (| tee), retry loop, and exit-code semantics are identical.

🤖 Generated with Claude Code

… PRs

Both run_opencode and run_gemini passed the full prompt as a single argv
argument (`opencode run -m M "$(cat prompt)"` / `gemini --prompt "$(cat
prompt)"`). On Linux the per-argument cap is MAX_ARG_STRLEN = 128KB; a PR with
a large diff produces a 150KB+ prompt, so the exec fails with "Argument list
too long" (exit 126) and validation hard-fails before the model ever runs.

Feed the prompt through stdin instead — neither CLI has a per-arg limit on a
piped stream:
- opencode reads a non-TTY stdin as the message (packages/opencode/src/cli/
  cmd/run.ts: `process.stdin.isTTY ? undefined : await Bun.stdin.text()`).
- gemini reads a non-TTY stdin as the prompt (packages/cli/src/gemini.tsx:
  `!process.stdin.isTTY` → readStdin() → pushed as --prompt); --prompt is also
  deprecated upstream.

`set -o pipefail` (already enabled) keeps $? as the CLI's exit code through the
`| tee` pipe, so retry/exit-code handling is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jbiskur jbiskur merged commit 9618150 into main Jun 10, 2026
10 checks passed
@jbiskur jbiskur deleted the fix/prompt-via-stdin-arg-limit branch June 10, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant