{"record":{"id":"f4dde0995384c123","repo":"t8y2/dbx","slug":"close-startup-warmup-s-w","errorCode":null,"errorMessage":"close startup warmup %s: %w","messagePattern":"close startup warmup (.+?): %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/rabbitmq/bench/agent_compare.go","lineNumber":156,"sourceCode":"}\n\nfunc benchmarkStartups(agents []agentSpec, warmups, iterations int) []benchmarkResult {\n\tfor warmup := 0; warmup < warmups; warmup++ {\n\t\torder := agents\n\t\tif warmup%2 == 1 {\n\t\t\torder = []agentSpec{agents[1], agents[0]}\n\t\t}\n\t\tfor _, agent := range order {\n\t\t\tprocess, _, err := startAgent(agent.Command)\n\t\t\tif err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"warm up startup %s: %w\", agent.Name, err))\n\t\t\t}\n\t\t\tif _, err := process.call(\"handshake\", map[string]any{}); err != nil {\n\t\t\t\tprocess.kill()\n\t\t\t\tpanic(fmt.Errorf(\"warm up handshake %s: %w\", agent.Name, err))\n\t\t\t}\n\t\t\tif err := process.close(); err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"close startup warmup %s: %w\", agent.Name, err))\n\t\t\t}\n\t\t}\n\t}\n\n\treadySamples := map[string][]float64{}\n\thandshakeSamples := map[string][]float64{}\n\trssSamples := map[string][]int64{}\n\treadyDurations := map[string]time.Duration{}\n\thandshakeDurations := map[string]time.Duration{}\n\tfor iteration := 0; iteration < iterations; iteration++ {\n\t\torder := agents\n\t\tif iteration%2 == 1 {\n\t\t\torder = []agentSpec{agents[1], agents[0]}\n\t\t}\n\t\tfor _, agent := range order {\n\t\t\tprocess, readyDuration, err := startAgent(agent.Command)\n\t\t\tif err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"start %s: %w\", agent.Name, err))","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/rabbitmq/bench/agent_compare.go#L138-L174","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check agent stderr for why it exited non-zero; fix the agent's shutdown/cleanup path so it exits 0 after replying to 'shutdown'.","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.","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.","Verify no external supervisor/oom-killer is killing children during the run.","Replace panic with an error return so warm-up failures degrade gracefully."],"exampleFix":"// before\nif err := process.close(); err != nil {\n\tpanic(fmt.Errorf(\"close startup warmup %s: %w\", agent.Name, err))\n}\n// after\nif err := process.close(); err != nil {\n\tlog.Printf(\"warmup close failed for %s: %v\", agent.Name, err)\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check: agent should exit 0 after a shutdown RPC\nstdin, _ := cmd.StdinPipe()\ncmd.Start()\nfmt.Fprintf(stdin, \"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"id\\\":1,\\\"method\\\":\\\"shutdown\\\",\\\"params\\\":{}}\\n\")\nstdin.Close()\nif err := cmd.Wait(); err != nil {\n\tlog.Fatalf(\"agent does not shut down cleanly: %v\", err)\n}","typeGuard":"func isExitStatus(err error) bool {\n\tvar exitErr *exec.ExitError\n\treturn errors.As(err, &exitErr)\n}\nfunc isKilled(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"signal: killed\")\n}","tryCatchPattern":"func safeClose(p *agentProcess, name string) (err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"close startup warmup %s: %v\", name, r)\n\t\t}\n\t}()\n\treturn p.close()\n}\n// Caller: log and continue for warmups; only fatal if Wait also failed.","preventionTips":["Make the agent reply to the shutdown RPC before exiting, and exit with status 0.","Do not treat stdin EOF as an excuse to skip the shutdown reply.","Test agent shutdown as part of CI so regressions surface early.","Distinguish shutdown RPC errors from Wait() errors in close() to ease diagnosis.","Log the child's exit code and signal on close failure."],"tags":["go","subprocess","shutdown","process-exit","panic"],"backgroundTag":"process-shutdown-failure","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}