Skip to main content

Troubleshooting

Most Model Peer failures are one of a handful of orchestration problems. Each has a distinct signature.

A reviewer hangs

Signature: one reviewer produces nothing for minutes; the run appears frozen.

Every consultation is bounded by a wall-clock timeout, 600 seconds by default:

model-peer review --timeout 300 # per reviewer
model-peer ask codex --timeout 120
model-peer review --timeout 0 # disable the bound

Progress is reported on stderr every 30 seconds, so a slow consultation is distinguishable from a dead one:

model-peer: Codex still working (120s of 600s).

On timeout, Model Peer signals the peer's whole process group, not just the process it launched. Vendor CLIs spawn helper processes that inherit stdout; killing only the parent leaves those helpers holding the pipe open and the hang survives the kill. ask exits 124 in this case, matching timeout(1).

A reviewer that times out is dropped from the panel rather than taking the whole run with it — see Partial panels below.

If a specific CLI hangs consistently, check it outside Model Peer:

codex exec --sandbox read-only "say hello" </dev/null

If that hangs too, the problem is the vendor CLI in your environment — usually authentication or network — and no Model Peer setting will fix it.

model-peer doctor --probe answers this directly. It runs one real consultation per CLI and reports which ones responded, so a hang shows up as no answer within Ns — nothing verified against that CLI alone rather than as a mysterious slow review.

Partial panels

A reviewer that times out, exits non-zero, or exits 0 having produced nothing is dropped and named. Synthesis proceeds as long as at least two reviewers produced a real review, because two independent views are the minimum that makes a cross-model review worth the name.

model-peer: Codex timed out after 600s; dropping it from the panel.
model-peer: synthesizing from 2 of 3 reviewers; the report will name the gaps.

The synthesizer is told which reviewers are missing and instructed to say so in the report — a gap in coverage is not evidence of safety, and a partial panel must never read as a complete one.

Fewer than two survivors is refused outright (exit 1). To restore the older behavior of refusing whenever any reviewer fails:

model-peer review --strict

Gemini returns nothing at all

Signature: Gemini exits 0 immediately, having written no output. Interactively it complains about an untrusted directory.

Gemini's folder-trust gate blocks work in directories it has not been told to trust, and headlessly that failure is silent. Model Peer passes --skip-trust so a non-interactive consultation is not a silent no-op.

This is safe here because Model Peer does not rely on the trust gate for its guarantees: Gemini is already run in Plan mode, with an explicit deny policy for write_file, replace, run_shell_command, enter_plan_mode, and exit_plan_mode, and with extensions disabled via -e none. See Safety boundaries.

The flag is feature-detected from gemini --help, so older builds that lack it are invoked as before.

Independently of the trust gate, any reviewer returning zero bytes is now treated as a failure rather than as "this model found no issues".

New files are missing from a review

Signature: a reviewer comments only on modified files and ignores a package you just created.

This was a real bug, fixed. git diff HEAD cannot see untracked files, and git status --short collapses a new directory to a single ?? src/ line — so an entire new package could reach a reviewer as one path with no filenames and no contents.

Review context now includes an add-diff for every untracked, non-ignored file:

<git_patch bytes="…" max_embedded_bytes="500000" includes_untracked="true">

.gitignore is respected, and binaries are summarized as Binary files … differ rather than dumped into the prompt. Confirm what a reviewer would see with:

git status --short --branch --untracked-files=all

If a file is missing from that list, it is ignored by Git and Model Peer will not send it.

A skill is installed but never fires

Only a skill's name and description reach the model's system prompt; the body loads when the model decides the skill applies. If a skill never activates, the description is usually the reason — it has to name the situations that should trigger it, not just describe what the skill is.

model-peer update rewrites the shipped description, so start there:

model-peer update --check

For Gemini specifically, check folder trust. In an untrusted directory it reports Skipping project agents due to untrusted folder and loads no project skills at all. Trust the directory once from an interactive gemini session.

gemini skills list # should list cross-model-review

Large diffs get truncated

Patches are embedded up to MODEL_PEER_MAX_DIFF_BYTES (default 500000). Beyond that the patch is truncated with an explicit marker and reviewers are told to inspect the listed files directly.

MODEL_PEER_MAX_DIFF_BYTES=1000000 model-peer review

Consider reviewing a narrower change instead — a reviewer given half a megabyte of patch tends toward generic findings.

Is the read-only contract actually holding?

model-peer doctor --probe

This runs one real consultation per installed CLI in a throwaway repository and checks on disk that nothing was written — a model's assurance that it could not write is not evidence. See the reference.

Worth running after upgrading any of the vendor CLIs, since that is when the behaviour Model Peer depends on is most likely to have changed.

Exit codes

CodeMeaning
0Success
1Too few reviewers completed, or update --check found missing or stale files
2Usage or validation error
64Refused by a chain guard — depth limit or self-consultation
124A consultation exceeded its timeout
127A required command is not installed