{"record":{"id":"e507ca0a86b0713a","repo":"t8y2/dbx","slug":"agent-request-panic-v","errorCode":null,"errorMessage":"agent request panic: %v","messagePattern":"agent request panic: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/oracle-go/main.go","lineNumber":646,"sourceCode":"\t}\n\trequests.Wait()\n\tif err := scanner.Err(); err != nil && !errors.Is(err, io.EOF) {\n\t\tfmt.Fprintf(os.Stderr, \"failed to read stdin: %v\\n\", err)\n\t}\n}\n\nfunc newRuntimeServer() *runtimeServer {\n\treturn &runtimeServer{sessions: map[string]*agentSession{}}\n}\n\nfunc (r *runtimeServer) handleLine(line string) (resp response, shutdown bool) {\n\tvar req request\n\t// Last-resort guard: a panic anywhere on the request path must not kill\n\t// the agent process and break the RPC stream, so convert it to a readable\n\t// error response instead of an end-of-stream failure.\n\tdefer func() {\n\t\tif recovered := recover(); recovered != nil {\n\t\t\tresp = errorResponse(req.ID, fmt.Errorf(\"agent request panic: %v\", recovered))\n\t\t\tshutdown = false\n\t\t}\n\t}()\n\tif err := json.Unmarshal([]byte(line), &req); err != nil {\n\t\treturn errorResponse(nil, err), false\n\t}\n\tif len(req.ID) == 0 {\n\t\treq.ID = json.RawMessage(\"1\")\n\t}\n\tresult, shouldShutdown, err := r.dispatch(req.Method, req.Params)\n\tif err != nil {\n\t\treturn errorResponse(req.ID, err), false\n\t}\n\treturn response{JSONRPC: \"2.0\", ID: req.ID, Result: result}, shouldShutdown\n}\n\nfunc (r *runtimeServer) dispatch(method string, params map[string]json.RawMessage) (any, bool, error) {\n\tswitch method {","sourceCodeStart":628,"sourceCodeEnd":664,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/oracle-go/main.go#L628-L664","documentation":"The agent process wraps each request handler in a recover() guard so a panic anywhere on the request path is converted into a structured error response (\"agent request panic: %v\") instead of crashing the process and breaking the JSON-RPC-over-stdout stream. The variable resp (the function's named return) carries this error back to the client, which sees it as the response's error field.","triggerScenarios":"Any runtime panic while handling a request line: nil map/slice access, type assertion failure on unmarshalled params, index out of range, or a bug in a method handler. The deferred recover catches it, sets resp to an errorResponse, and prevents shutdown.","commonSituations":"Client sends params of unexpected shape (missing field, wrong type) that a handler asserts; query results larger than expected triggering an index bug; a driver/runtime internal error surfacing as a panic under concurrency.","solutions":["Read the %v detail in the response error to identify the panicking value/operation","Fix the handler bug revealed by the panic (nil checks, safe type assertions, bounds checks)","Validate/sanitize request params on the client before sending so handlers receive expected shapes","Update the agent binary if the panic is a known fixed bug","Report the stack (add debug logging around the recover) to the driver maintainers if reproducible"],"exampleFix":"// handler before\nlimit := params[\"limit\"].(int) // panics if float64 or missing\n// after\nlimit, ok := params[\"limit\"].(float64)\nif !ok { return errorResponse(req.ID, fmt.Errorf(\"invalid limit\")) }","handlingStrategy":"try-catch","validationCode":"# client-side: shape-check params before sending to avoid handler panics\nrequired = {\"sql\": str, \"params\": (dict, type(None))}\nfor key, types in required.items():\n    if key in payload and not isinstance(payload[key], types):\n        raise TypeError(f\"param {key!r} must be {types}\")","typeGuard":"def is_valid_response(resp: dict) -> bool:\n    return isinstance(resp, dict) and (\"error\" in resp or \"result\" in resp) and not (\"error\" in resp and \"result\" in resp)","tryCatchPattern":"try:\n    response = send_request(line)\nexcept AgentRPCError as e:\n    if \"agent request panic\" in str(e):\n        log.error(\"agent panicked on request: %s\", e)\n        # retry once with sanitized params or fail fast; do not reconnect blindly\n        raise\n    raise","preventionTips":["Validate request params against a schema before sending","Pin agent versions known to be panic-free; update on fixes","Capture the panic detail from the error response when filing bugs","Add server-side nil/type-assertion guards in handlers"],"tags":["oracle","panic","rpc","recovery"],"backgroundTag":"agent-request-panic","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}