{"record":{"id":"ca45c4bc92048006","repo":"t8y2/dbx","slug":"warm-up-handshake-s-w","errorCode":null,"errorMessage":"warm up handshake %s: %w","messagePattern":"warm up handshake (.+?): %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"agents/drivers/rabbitmq/bench/agent_compare.go","lineNumber":153,"sourceCode":"\t\t\t))\n\t\t}\n\t}\n}\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 {","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/rabbitmq/bench/agent_compare.go#L135-L171","documentation":"This panic wraps any failure from the agent's JSON-RPC 'handshake' call during the startup warm-up phase of the benchmark. The benchmark spawns each agent as a subprocess, waits for its ready line, then writes a JSON-RPC handshake request to its stdin and reads the response. The call fails when the agent process dies, closes its stdout, returns malformed/unexpected JSON, or replies with a JSON-RPC error — so the wrapped error is usually 'agent response unavailable: <read error>' or an agent-side error message. It is thrown via panic because in this bench harness a warm-up failure means the environment is broken and the whole run is invalid.","triggerScenarios":"During benchmarkStartups warm-ups: startAgent() succeeds but process.call(\"handshake\") fails — the agent crashes after emitting its ready line, exits before answering (broken binary/JAR, JVM crash, OOM kill), writes nothing to stdout so reader.Scan() returns false ('agent response unavailable'), returns JSON whose id mismatches, or returns a JSON-RPC error object.","commonSituations":"JAVA_AGENT_JAR or GO_AGENT points to a stale/Corrupted artifact that starts but dies on first request; the JVM hits an OOM or UnsupportedClassVersionError mid-run; the agent was rebuilt with an incompatible handshake protocol (id or field mismatch); resource limits (ulimit, cgroup) kill the child during repeated rapid spawns.","solutions":["Read the agent's stderr (inherited to os.Stderr) for the crash output; fix the underlying agent crash (missing config, bad JAR, protocol mismatch).","Verify JAVA_AGENT_JAR/GO_AGENT point to freshly built, runnable artifacts — run the agent manually and issue a handshake request over stdin.","Rebuild both agents so their JSON-RPC handshake matches the harness format ({\"id\":n,\"result\":...} with matching ids).","Check machine memory/ulimits; the benchmark spawns processes repeatedly and children can be OOM-killed.","As a code fix, replace panic with error return so partial results can be reported instead of aborting the run."],"exampleFix":"// before\nif _, err := process.call(\"handshake\", map[string]any{}); err != nil {\n\tprocess.kill()\n\tpanic(fmt.Errorf(\"warm up handshake %s: %w\", agent.Name, err))\n}\n// after\nif _, err := process.call(\"handshake\", map[string]any{}); err != nil {\n\tprocess.kill()\n\tlog.Printf(\"warm up handshake failed for %s: %v\", agent.Name, err)\n\treturn nil, fmt.Errorf(\"warm up handshake %s: %w\", agent.Name, err)\n}","handlingStrategy":"try-catch","validationCode":"// Before running the benchmark, verify the agent artifact and binary:\njar := os.Getenv(\"JAVA_AGENT_JAR\")\nif _, err := os.Stat(jar); err != nil {\n\tlog.Fatalf(\"JAVA_AGENT_JAR not found: %v\", err)\n}\ncmd := exec.Command(\"java\", \"-jar\", jar)\ncmd.Stdin = strings.NewReader(\"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"id\\\":1,\\\"method\\\":\\\"handshake\\\",\\\"params\\\":{}}\\n\")\nout, err := cmd.Output()\nif err != nil || !strings.Contains(string(out), \"\\\"result\\\"\") {\n\tlog.Fatalf(\"agent handshake smoke test failed: %v\", err)\n}","typeGuard":"// Narrow the wrapped error to detect the read-EOF case from call()\nfunc isResponseUnavailable(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"agent response unavailable\")\n}\nfunc isIDMismatch(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"does not match request id\")\n}","tryCatchPattern":"// Go uses recover instead of try/catch; scope it to the warm-up phase\nfunc safeWarmupHandshake(p *agentProcess, name string) (err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tp.kill()\n\t\t\terr = fmt.Errorf(\"warm up handshake %s: %v\", name, r)\n\t\t}\n\t}()\n\t_, err = p.call(\"handshake\", map[string]any{})\n\treturn err\n}","preventionTips":["Smoke-test each agent binary with a single handshake before the benchmark loop.","Ensure agents log to stderr only; stdout is reserved for JSON-RPC frames.","Pin and rebuild agent artifacts together with the harness so protocols stay in sync.","Set generous memory limits so the JVM is not OOM-killed during startup.","Prefer returning errors over panic in library-style harness code."],"tags":["go","jsonrpc","subprocess","handshake","panic"],"backgroundTag":"handshake-failed","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"}