t8y2/dbx · error · RuntimeError

agent exited before {method}

Error message

agent exited before {method}

What it means

AgentProcess.call raises this RuntimeError when an RPC method is invoked after the agent subprocess's stdout reader loop ended (the `exited` event is set), meaning the child process died or closed its stdout. The harness refuses to send a request to a dead process and fails fast, attaching captured stderr via _failure for diagnosis.

Source

Thrown at agents/drivers/argo-go/bench/agent_compare.py:80

            with self.request_lock:
                response_queue = self.pending.get(response_id)
            if response_queue is not None:
                response_queue.put(response)
        self.exited.set()
        self.ready.set()
        with self.request_lock:
            pending = list(self.pending.values())
        for response_queue in pending:
            response_queue.put(RuntimeError(self._failure("agent process exited")))

    def _drain_stderr(self) -> None:
        assert self.process.stderr is not None
        for line in self.process.stderr:
            self.stderr_lines.append(line.rstrip())

    def call(self, method: str, params: dict | None = None) -> object:
        if self.exited.is_set():
            raise RuntimeError(self._failure(f"agent exited before {method}"))
        with self.request_lock:
            self.request_id += 1
            request_id = self.request_id
            response_queue: queue.Queue = queue.Queue(maxsize=1)
            self.pending[request_id] = response_queue
        request = {
            "jsonrpc": "2.0",
            "id": request_id,
            "method": method,
            "params": params or {},
        }
        try:
            assert self.process.stdin is not None
            with self.write_lock:
                self.process.stdin.write(json.dumps(request, separators=(",", ":")) + "\n")
                self.process.stdin.flush()
            response = response_queue.get(timeout=env_float("BENCH_RPC_TIMEOUT", 180.0))
        except queue.Empty as error:

View on GitHub (pinned to c0390bff16)

Solutions

  1. Inspect process.stderr_lines (included in the failure message) for the agent's crash output and fix the underlying crash
  2. Re-check the agent command/artifact path in BENCH_CANDIDATES and rebuild the agent so it starts cleanly
  3. Catch RuntimeError in the driver, call close(), and restart AgentProcess for the candidate before retrying the workload
  4. Raise BENCH_RPC_TIMEOUT or reduce workload size if the agent is being killed by OOM during runs
  5. Verify the agent still emits a ready line and keeps stdout open for the whole session (protocol regression check)

Example fix

// before
rows = process.call("execute_query", params)
// after
try:
    rows = process.call("execute_query", params)
except RuntimeError as e:
    if "agent exited before" in str(e):
        process = AgentProcess(candidate)  # restart crashed agent
        rows = process.call("execute_query", params)
    else:
        raise
Defensive patterns

Strategy: try-catch

Validate before calling

if process.exited.is_set():
    process = AgentProcess(process.candidate)  # restart before calling
rows = process.call("execute_query", params)

Type guard

def agent_alive(process) -> bool:
    return process.process.poll() is None and not process.exited.is_set()

Try / catch

try:
    result = process.call(method, params)
except RuntimeError as e:
    if "agent exited before" in str(e):
        log(process.stderr_lines)
        process = AgentProcess(process.candidate)
        result = process.call(method, params)
    else:
        raise

Prevention

When it happens

Trigger: Any call() to method X after the agent process exited: child crashed on startup or mid-run, closed stdout, was killed (OOM, signal), or a previous call timed out and the process was torn down while execute_workload/close/probe_paging/probe_failure_semantics/benchmark_workload/tdengine_websocket_live_compatibility kept issuing calls.

Common situations: Agent binary built from an incompatible version crashes when given a workload; OOM killer terminates a memory-heavy candidate during long benchmark runs; agent panics on a malformed SQL statement in a failure-semantics probe; PYTHONUNBUFFERED/stdio framing mismatch causes the reader loop to hit EOF early.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/3493fa7d98c6277e. Report an issue: GitHub.