You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If the docker exec child has already exited and been reaped by the time the asyncio.wait_for timeout fires, process.terminate() raises ProcessLookupError. That escapes the except TimeoutError block, so the RuntimeError("Command timed out after Ns") is never raised.
Since the hardening execs run inside the try in _verify_rollout, the exception lands in the generic except Exception branch:
str(ProcessLookupError()) is empty, so the rollout is recorded as literally verifier crashed: with nothing after the colon, rewards: null, and an empty verifier/ directory because the verifier was never constructed. The signal that this was a timeout — the one thing #1058 and #1062 are about — is destroyed on the way out.
Reproducible example code
bench eval run --tasks-dir <tasks> --include <task> \
--agent claude-agent-acp --model azure/anthropic/claude-opus-5 \
--reasoning-effort max
Probabilistic: it needs the hardening exec to time out and its child to exit in the same window. Five long rollouts of one task hit it; short rollouts of the same task at the same head never did.
Traceback
Not visible in a stock build, which is the point of this report. After patching _verify_rollout locally to print the type and the traceback:
Docker.exec should guard the teardown, e.g. with contextlib.suppress(ProcessLookupError): process.terminate() and the same around process.kill(), so a timeout is always reported as the timeout it is. With that, this failure becomes the case fix(sandbox): use the verifier-setup budget for hardening execs #1062 fixes.
_verify_rollout's generic branch should include the exception type, since f"verifier crashed: {e}" is empty for any exception with no args. f"verifier crashed: {type(e).__name__}: {e}" would have made this a five-minute diagnosis rather than a five-occurrence mystery.
Additional context
Worth ruling out for anyone who finds this by symptom: it is not resource exhaustion. I logged docker stats every 30 s across nineteen containers of these runs. The peak was 620 MiB against a 7.75 GiB limit, and the container that failed was at 69 MiB (0.87 %) at the moment of the crash. Nothing was OOM-killed.
The practical cost is that a finished agent rollout — hours of work and, in one of these, 26 M tokens — is scored as nothing, and none of its deliverables are preserved, because verifier/ is cleared before the step that dies.
Required prerequisites
main.What version of BenchFlow are you using?
0.7.5 (PyPI).
System information
Host: macOS 15 (arm64, 14 cores), Python 3.12. Sandbox: Docker. Agent: claude-agent-acp with
azure/anthropic/claude-opus-5, reasoning effort max. One task perbench eval run,--concurrency 4, agent budget 4 h.Problem description
This is the same code path as #1058 but a different failure, and #1062 does not cover it.
Docker.exechandles a timeout like this (benchflow/sandbox/docker.py, both exec helpers, around lines 360-380 and 412-430):If the
docker execchild has already exited and been reaped by the time theasyncio.wait_fortimeout fires,process.terminate()raisesProcessLookupError. That escapes theexcept TimeoutErrorblock, so theRuntimeError("Command timed out after Ns")is never raised.Since the hardening execs run inside the
tryin_verify_rollout, the exception lands in the genericexcept Exceptionbranch:str(ProcessLookupError())is empty, so the rollout is recorded as literallyverifier crashed:with nothing after the colon,rewards: null, and an emptyverifier/directory because the verifier was never constructed. The signal that this was a timeout — the one thing #1058 and #1062 are about — is destroyed on the way out.Reproducible example code
Probabilistic: it needs the hardening exec to time out and its child to exit in the same window. Five long rollouts of one task hit it; short rollouts of the same task at the same head never did.
Traceback
Not visible in a stock build, which is the point of this report. After patching
_verify_rolloutlocally to print the type and the traceback:Stock builds print only:
Expected behavior
Two things:
Docker.execshould guard the teardown, e.g.with contextlib.suppress(ProcessLookupError): process.terminate()and the same aroundprocess.kill(), so a timeout is always reported as the timeout it is. With that, this failure becomes the case fix(sandbox): use the verifier-setup budget for hardening execs #1062 fixes._verify_rollout's generic branch should include the exception type, sincef"verifier crashed: {e}"is empty for any exception with no args.f"verifier crashed: {type(e).__name__}: {e}"would have made this a five-minute diagnosis rather than a five-occurrence mystery.Additional context
Worth ruling out for anyone who finds this by symptom: it is not resource exhaustion. I logged
docker statsevery 30 s across nineteen containers of these runs. The peak was 620 MiB against a 7.75 GiB limit, and the container that failed was at 69 MiB (0.87 %) at the moment of the crash. Nothing was OOM-killed.The practical cost is that a finished agent rollout — hours of work and, in one of these, 26 M tokens — is scored as nothing, and none of its deliverables are preserved, because
verifier/is cleared before the step that dies.