Skip to content

Windows: system prompts over ~8 KB fail inference with "The command line is too long" (follow-up to #1534) #2003

Description

@aveneri

Version: 7.40.4 · Platform: Windows 10 · Bun: 1.3.10 · claude-code: 2.1.76

This is a follow-up to #1534, which fixed the same class of bug on Linux. The threshold that fix chose is correct for Linux and macOS but is roughly 12× too high for Windows, so Windows installs are still broken.

What happens

Every Inference.ts call carrying a system prompt larger than ~8 KB fails before reaching the model:

inference failed: The command line is too long.

The most visible casualty is the memory subsystem. MemoryReviewer's system prompt is ~9.4 KB, so memory review has never completed on Windows. MemoryHealthCheck reports overall: critical, reviewer.status: parse-failed, priorSuccesses: 0, and memory sits permanently at grade F with no curation runs.

Root cause

LIFEOS/TOOLS/Inference.ts spills the system prompt to a temp file only above 100,000 bytes:

let systemPromptFile: string | null = null;
let systemPromptArgs = ['--system-prompt', options.systemPrompt];
if (Buffer.byteLength(options.systemPrompt, 'utf8') > 100_000) {
  systemPromptFile = join(tmpdir(), `lifeos-sysprompt-${randomUUID()}.md`);
  writeFileSync(systemPromptFile, options.systemPrompt, { mode: 0o600 });
  systemPromptArgs = ['--system-prompt-file', systemPromptFile];
}

The comment directly above it documents the reasoning: the threshold was chosen against Linux's per-arg MAX_ARG_STRLEN (~128 KiB), and it notes macOS has no per-arg cap. Windows was not considered, and Windows fails by a different mechanism entirely:

  1. resolveClaudeBin()Bun.which("claude") returns claude.cmd, a batch shim, not a native executable.
  2. Spawning a .cmd on Windows goes through cmd.exe.
  3. cmd.exe caps the total command line at 8,191 characters — not per-argument.

So a 9.4 KB system prompt sits comfortably below the 100 KB spill threshold and comfortably above the 8,191 ceiling. It rides argv, and cmd.exe rejects the whole line before the model is ever reached.

Reproduce

On Windows, with claude installed via npm so that claude.cmd is what lands on PATH:

bun LIFEOS/TOOLS/Inference.ts --level low "$(python -c 'print("x"*9000)')" "Reply with exactly: OK"
# → inference failed: The command line is too long.

A 6,000-character system prompt succeeds; 9,000 fails. The exact breaking size depends on the combined length of the other flags, since the limit applies to the whole line.

Impact

Not memory-specific. Every caller with a system prompt over ~8 KB is affected on Windows. Memory is simply the subsystem that runs on a schedule and reports its own health, so it is where the failure becomes visible.

Suggested fix

Make the spill threshold platform-aware. Unix behavior is unchanged.

+    // Windows needs a far lower ceiling than the Linux cap above. `claude`
+    // resolves to `claude.cmd`, a batch shim, so the child is spawned through
+    // cmd.exe — and cmd.exe caps the TOTAL command line at 8191 characters,
+    // not per-arg. That is ~12x below the 100 KB threshold, so any system
+    // prompt over ~8 KB dies with "The command line is too long." before the
+    // model is ever reached. The MemoryReviewer prompt is ~9.4 KB, which is
+    // why memory review never completes on Windows (priorSuccesses: 0).
+    // 6 KB leaves headroom for the binary path and the ~200 chars of other
+    // flags that share the line.
+    const ARGV_SYSTEM_PROMPT_LIMIT = process.platform === 'win32' ? 6_000 : 100_000;
     let systemPromptFile: string | null = null;
     let systemPromptArgs = ['--system-prompt', options.systemPrompt];
-    if (Buffer.byteLength(options.systemPrompt, 'utf8') > 100_000) {
+    if (Buffer.byteLength(options.systemPrompt, 'utf8') > ARGV_SYSTEM_PROMPT_LIMIT) {
       systemPromptFile = join(tmpdir(), `lifeos-sysprompt-${randomUUID()}.md`);
       writeFileSync(systemPromptFile, options.systemPrompt, { mode: 0o600 });
       systemPromptArgs = ['--system-prompt-file', systemPromptFile];
     }

Verified

Applied locally against 7.40.4:

Check Before After
9.4 KB system prompt spills to file on win32 no, rode argv yes
Live inference smoke (--level low) fails returns OK
MemoryReviewer review never completed runs to completion

Happy to open a PR if that is useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions