Skip to content

Mitigate ARG_MAX/E2BIG by rewriting inline prompt expansion to stdin in AWF agent command#1999

Closed
Copilot wants to merge 6 commits intomainfrom
copilot/fix-arg-max-exceeded-error
Closed

Mitigate ARG_MAX/E2BIG by rewriting inline prompt expansion to stdin in AWF agent command#1999
Copilot wants to merge 6 commits intomainfrom
copilot/fix-arg-max-exceeded-error

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 15, 2026

Large gh-aw workflows can inline 100KB+ prompts into argv via --prompt "$(cat ...)", which combines with container env size and can exceed Linux ARG_MAX, failing process start with E2BIG. This change adds an AWF-side mitigation by keeping prompt payload on disk and passing it via stdin instead of argv.

  • Command rewrite for inline prompt expansions

    • Detects gh-aw style inline prompt patterns in agentCommand:
      • --prompt "$(cat /path/to/prompt.txt)"
      • --prompt $(cat /path/to/prompt.txt)
    • Rewrites execution form to:
      • cat '/path/to/prompt.txt' | ... --prompt -
    • Preserves normal literal prompts (no rewrite).
  • ARG_MAX diagnostics improvement

    • Expands existing --env-all warning from env-only size to estimated combined argv + env size.
    • Surfaces clearer risk signal before runtime execve failure.
  • Focused coverage

    • Adds unit tests for:
      • quoted inline $(cat ...) rewrite
      • single-quoted prompt-file paths (including spaces)
      • unquoted inline $(cat ...) rewrite
      • non-inline literal --prompt no-op behavior
# before
node ... --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)" --allow-all-tools

# after
cat '/tmp/gh-aw/aw-prompts/prompt.txt' | node ... --prompt - --allow-all-tools

Copilot AI changed the title [WIP] Fix E2BIG error due to large prompts in argv Mitigate ARG_MAX/E2BIG by rewriting inline prompt expansion to stdin in AWF agent command Apr 15, 2026
Copilot AI requested a review from lpcox April 15, 2026 21:13
@lpcox lpcox marked this pull request as ready for review April 16, 2026 00:09
@lpcox lpcox requested a review from Mossaka as a code owner April 16, 2026 00:09
Copilot AI review requested due to automatic review settings April 16, 2026 00:09
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Mitigates Linux ARG_MAX / E2BIG failures caused by large inline prompt expansions (e.g. --prompt "$(cat ...)") by rewriting the agent command to feed the prompt via stdin, and improves preflight diagnostics by warning on estimated combined argv + env size.

Changes:

  • Adds a command rewriter in generateDockerCompose() to detect --prompt $(cat ...) / --prompt "$(cat ...)" and convert it to cat 'file' | ... --prompt -.
  • Enhances the existing --env-all warning to estimate combined argv + env bytes (instead of env-only).
  • Adds unit tests validating the rewrite behavior for quoted/unquoted forms and a no-op for literal prompts.
Show a summary per file
File Description
src/docker-manager.ts Introduces inline-prompt rewrite + enhanced argv+env sizing warning; switches compose command to use rewritten agent command.
src/docker-manager.test.ts Adds test coverage for prompt rewrite variants and ensures literal prompts are not rewritten.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 2

Comment thread src/docker-manager.ts Outdated
Comment on lines +122 to +126
const rewrittenCommand = `${agentCommand.slice(0, inlinePrompt.start)}--prompt -${agentCommand.slice(inlinePrompt.end)}`;
if (rewrittenCommand === agentCommand) return agentCommand;

logger.warn(`Rewriting inline prompt expansion to stdin pipe to avoid ARG_MAX/E2BIG: ${promptPath}`);
return `cat ${shellQuote(promptPath)} | ${rewrittenCommand}`;
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rewrite currently prepends cat ... | to the entire agentCommand. This changes shell semantics when agentCommand is a compound command (e.g. contains &&, ;, an existing pipe, or redirects): stdin gets consumed by the left-most command and the pipeline exit status/precedence can differ from the original, potentially breaking execution.

Also, shellQuote(promptPath) forces single-quoting, which will prevent any $VAR expansion that may have worked in the original $(cat $VAR/...) or $(cat "$VAR") form.

Consider either (a) restricting the rewrite to “simple” commands (no shell operators / variable expansions in the prompt path) and otherwise leaving the command unchanged, or (b) rewriting in-place to use --prompt - with an input redirection that applies only to the copilot invocation, while preserving the original path quoting/expansion semantics.

Copilot uses AI. Check for mistakes.
Comment thread src/docker-manager.test.ts Outdated
Comment on lines +1298 to +1352
it('should rewrite inline --prompt $(cat ...) to stdin pipe to avoid ARG_MAX expansion', () => {
const configWithInlinePrompt = {
...mockConfig,
agentCommand: 'node /tmp/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)" --allow-all-tools',
};
const result = generateDockerCompose(configWithInlinePrompt, mockNetworkConfig);
const agent = result.services.agent;

expect(agent.command).toEqual([
'/bin/bash',
'-c',
'cat \'/tmp/gh-aw/aw-prompts/prompt.txt\' | node /tmp/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --prompt - --allow-all-tools',
]);
});

it('should rewrite inline --prompt $(cat ...) when cat path is single-quoted', () => {
const configWithQuotedPath = {
...mockConfig,
agentCommand: 'node /tmp/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --prompt "$(cat \'/tmp/gh-aw/aw-prompts/prompt with spaces.txt\')" --allow-all-tools',
};
const result = generateDockerCompose(configWithQuotedPath, mockNetworkConfig);
const agent = result.services.agent;

expect(agent.command).toEqual([
'/bin/bash',
'-c',
'cat \'/tmp/gh-aw/aw-prompts/prompt with spaces.txt\' | node /tmp/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --prompt - --allow-all-tools',
]);
});

it('should rewrite unquoted --prompt $(cat ...) form', () => {
const configWithUnquotedInlinePrompt = {
...mockConfig,
agentCommand: 'node /tmp/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --prompt $(cat /tmp/gh-aw/aw-prompts/prompt.txt) --allow-all-tools',
};
const result = generateDockerCompose(configWithUnquotedInlinePrompt, mockNetworkConfig);
const agent = result.services.agent;

expect(agent.command).toEqual([
'/bin/bash',
'-c',
'cat \'/tmp/gh-aw/aw-prompts/prompt.txt\' | node /tmp/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --prompt - --allow-all-tools',
]);
});

it('should not rewrite regular literal --prompt values', () => {
const configWithLiteralPrompt = {
...mockConfig,
agentCommand: 'copilot --prompt "hello world"',
};
const result = generateDockerCompose(configWithLiteralPrompt, mockNetworkConfig);
const agent = result.services.agent;

expect(agent.command).toEqual(['/bin/bash', '-c', 'copilot --prompt "hello world"']);
});
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests cover literal paths (including single-quoted paths with spaces), but there’s no coverage for prompt file paths that rely on shell expansion (e.g. $RUNNER_TEMP/prompt.txt or "$GH_AW_PROMPT"). Given the rewrite logic currently normalizes then single-quotes the extracted path, adding a test for an env-var-based path would help catch regressions/semantic changes once the quoting/rewriting strategy is adjusted.

Copilot uses AI. Check for mistakes.
Replace 'cat file | command --prompt -' with 'command --prompt - < file'
to preserve shell semantics for compound commands (pipes, &&, ;).

Preserve original path quoting so env-var paths like $RUNNER_TEMP expand
correctly at runtime instead of being force single-quoted.

Add test coverage for env-var prompt paths and compound commands.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 85.35% 85.56% 📈 +0.21%
Statements 85.24% 85.41% 📈 +0.17%
Functions 87.96% 88.10% 📈 +0.14%
Branches 77.95% 78.01% 📈 +0.06%
📁 Per-file Coverage Changes (1 files)
File Lines (Before → After) Statements (Before → After)
src/docker-manager.ts 86.8% → 87.5% (+0.68%) 86.4% → 86.9% (+0.53%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

@github-actions
Copy link
Copy Markdown
Contributor

Smoke test results (run 24485544682)

  • ✅ GitHub MCP: "feat: add smoke test for Copilot CLI offline BYOK mode" / "fix(api-proxy): fix Gemini API_KEY_INVALID with credential isolation"
  • ✅ Playwright: github.com title contains "GitHub"
  • ✅ File write: /tmp/gh-aw/agent/smoke-test-claude-24485544682.txt created
  • ✅ Bash verify: file read back successfully

Overall: PASS

💥 [THE END] — Illustrated by Smoke Claude

@github-actions
Copy link
Copy Markdown
Contributor

Smoke test results:

  • feat: add smoke test for Copilot CLI offline BYOK mode ✅ (GitHub MCP review)
  • fix(api-proxy): fix Gemini API_KEY_INVALID with credential isolation ✅ (GitHub MCP review)
  • safeinputs-gh PR query ❌ (tool unavailable in this run)
  • Playwright github.com title contains "GitHub" ✅
  • Tavily web search ❌ (Tavily MCP unavailable)
  • File write/readback in /tmp/gh-aw/agent ✅
  • Discussion interaction ✅
  • npm ci && npm run build ✅
    Overall status: FAIL

🔮 The oracle has spoken through Smoke Codex

@github-actions github-actions Bot mentioned this pull request Apr 16, 2026
@lpcox
Copy link
Copy Markdown
Collaborator

lpcox commented Apr 16, 2026

abandoning since copilot cli does not support --prompt -

@lpcox lpcox closed this Apr 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

E2BIG: large prompts inlined into argv via --prompt "$(cat ...)" exceed ARG_MAX

3 participants