t8y2/dbx · error

close startup warmup %s: %w

Error message

close startup warmup %s: %w

What it means

This panic wraps an error from process.close() during the startup warm-up loop. close() sends a JSON-RPC 'shutdown' request, closes stdin, and waits for the child process; it returns the shutdown-call error if present, otherwise the cmd.Wait() error. A failure here means the agent refused/failed the shutdown RPC or exited abnormally (non-zero status, signal kill), which the harness treats as a broken environment and aborts the benchmark.

Source

Thrown at agents/drivers/rabbitmq/bench/agent_compare.go:156

}

func benchmarkStartups(agents []agentSpec, warmups, iterations int) []benchmarkResult {
	for warmup := 0; warmup < warmups; warmup++ {
		order := agents
		if warmup%2 == 1 {
			order = []agentSpec{agents[1], agents[0]}
		}
		for _, agent := range order {
			process, _, err := startAgent(agent.Command)
			if err != nil {
				panic(fmt.Errorf("warm up startup %s: %w", agent.Name, err))
			}
			if _, err := process.call("handshake", map[string]any{}); err != nil {
				process.kill()
				panic(fmt.Errorf("warm up handshake %s: %w", agent.Name, err))
			}
			if err := process.close(); err != nil {
				panic(fmt.Errorf("close startup warmup %s: %w", agent.Name, err))
			}
		}
	}

	readySamples := map[string][]float64{}
	handshakeSamples := map[string][]float64{}
	rssSamples := map[string][]int64{}
	readyDurations := map[string]time.Duration{}
	handshakeDurations := map[string]time.Duration{}
	for iteration := 0; iteration < iterations; iteration++ {
		order := agents
		if iteration%2 == 1 {
			order = []agentSpec{agents[1], agents[0]}
		}
		for _, agent := range order {
			process, readyDuration, err := startAgent(agent.Command)
			if err != nil {
				panic(fmt.Errorf("start %s: %w", agent.Name, err))

View on GitHub (pinned to c0390bff16)

Solutions

  1. Check agent stderr for why it exited non-zero; fix the agent's shutdown/cleanup path so it exits 0 after replying to 'shutdown'.
  2. If the agent intentionally exits on stdin EOF before replying, either reply to shutdown first in the agent, or treat stdin-close as the shutdown signal in the harness.
  3. In close(), ignore the shutdown-call error and report only the Wait() error, since a dead-but-reaped child is acceptable at end of warm-up.
  4. Verify no external supervisor/oom-killer is killing children during the run.
  5. Replace panic with an error return so warm-up failures degrade gracefully.

Example fix

// before
if err := process.close(); err != nil {
	panic(fmt.Errorf("close startup warmup %s: %w", agent.Name, err))
}
// after
if err := process.close(); err != nil {
	log.Printf("warmup close failed for %s: %v", agent.Name, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check: agent should exit 0 after a shutdown RPC
stdin, _ := cmd.StdinPipe()
cmd.Start()
fmt.Fprintf(stdin, "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"shutdown\",\"params\":{}}\n")
stdin.Close()
if err := cmd.Wait(); err != nil {
	log.Fatalf("agent does not shut down cleanly: %v", err)
}

Type guard

func isExitStatus(err error) bool {
	var exitErr *exec.ExitError
	return errors.As(err, &exitErr)
}
func isKilled(err error) bool {
	return err != nil && strings.Contains(err.Error(), "signal: killed")
}

Try / catch

func safeClose(p *agentProcess, name string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("close startup warmup %s: %v", name, r)
		}
	}()
	return p.close()
}
// Caller: log and continue for warmups; only fatal if Wait also failed.

Prevention

When it happens

Trigger: In benchmarkStartups warm-up: after a successful handshake, process.close() fails — the 'shutdown' RPC write/read fails ('agent response unavailable'), or command.Wait() returns an error such as 'exit status 1' or 'signal: killed', indicating the agent did not shut down cleanly.

Common situations: The agent binary handles 'shutdown' but exits non-zero (e.g. logs an error on cleanup); the agent exits immediately on stdin close before replying to shutdown, so the call errors; Wait() reports 'signal: killed' because an external watchdog/oom-killer terminated the JVM; a buggy agent version changed the shutdown semantics.

Related errors


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