Skip to content

E2BIG: argument list too long, posix_spawn 'git' on revert in large repos (~19K files) #22533

Closed

Description

@cristianmiranda

Description

When attempting to revert a message in a session running in a large repository (~19K tracked files), the revert operation fails with:

E2BIG: argument list too long, posix_spawn 'git'

The error is reproducible — every revert attempt in this project fails.

Environment

  • opencode version: 1.4.4
  • OS: Arch Linux 6.19.11 (x86_64)
  • ARG_MAX: 2,097,152 bytes (2 MB)
  • Repo size: 19,111 tracked git files, average path length ~103 bytes (~2 MB total path data)

Reproduction

  1. Open a session in a git repo with ~19K+ tracked files
  2. Send a message to the agent
  3. Attempt to revert the message

Logs

ERROR 2026-04-15T02:30:59 +88ms service=server error=E2BIG: argument list too long, posix_spawn 'git' failed

From ~/.local/share/opencode/log/:

service=server method=POST path=/session/<id>/revert request
service=server messageID=<id> revert
ERROR service=server error=E2BIG: argument list too long, posix_spawn 'git' failed

Root Cause

In packages/opencode/src/snapshot/index.ts, the add(), patch(), and diffFull() functions pass all changed/untracked file paths as command-line arguments to git check-ignore:

const checkArgs = [
  ...quote,
  "--git-dir", path.join(state.worktree, ".git"),
  "--work-tree", state.worktree,
  "check-ignore", "--no-index",
  "--", ...all,  // <-- ALL files as CLI args
]
const check = yield* git(checkArgs, { cwd: state.directory })

During a revert, the snapshot index diverges from the working tree, causing diff-files and ls-files --others to return a large number of files. With ~19K files × ~103 bytes average path + config flags + env vars, the total argument size exceeds the Linux ARG_MAX limit of 2 MB.

The same pattern also appears in:

  • patch() — check-ignore --no-index -- ...files
  • diffFull() — check-ignore --no-index -- ...files
  • add() — git rm --cached -f -- ...ignoredFiles

Suggested Fix

Replace CLI argument passing with stdin-based communication for git check-ignore:

// Instead of:
git(["check-ignore", "--no-index", "--", ...files])

// Use stdin (-z for null-separated, --stdin for reading from stdin):
git(["check-ignore", "--no-index", "--stdin", "-z"], { stdin: files.join("\0") })

This avoids the OS argument length limit entirely. The same pattern should be applied to git rm --cached calls (using --stdin or xargs-style batching).

Alternatively, the file list could be batched into chunks that stay well under ARG_MAX.

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    perfIndicates a performance issue or need for optimization
    on Apr 15, 2026
  2. niceilm commented on Apr 15, 2026

    @niceilm

    I also experienced the same issue with versions 1.4.4 and 1.4.5.

    I confirmed that it works after downgrading to 1.4.3.

    I will work on the previous version for now.

    I hope it gets resolved quickly.

  3. cristianmiranda commented on Apr 15, 2026

    @cristianmiranda
    Author

    @niceilm you can set "snapshot": false in the meantime

  4. niceilm commented on Apr 16, 2026

    @niceilm

    It was resolved in version 1.4.6, so it works well now.

    Thank you for the quick fix.

  5. cristianmiranda commented on Apr 16, 2026

    @cristianmiranda
    Author

    I can confirmed this is fixed in 1.4.6
    Closing the issue. Thank you for the fix! 🎉

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

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)perfIndicates a performance issue or need for optimization

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions