{"record":{"id":"a50c0e51be45ac6a","repo":"t8y2/dbx","slug":"agent-session-limit-reached-d-a50c0e","errorCode":null,"errorMessage":"Agent session limit reached: %d","messagePattern":"Agent session limit reached: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/etcd2-go/main.go","lineNumber":234,"sourceCode":"\t\tdefer session.mu.Unlock()\n\t\tresult, err := session.state.handle(method, params)\n\t\treturn result, false, err\n\t}\n}\n\nfunc requiredSessionID(params map[string]json.RawMessage) string {\n\treturn strings.TrimSpace(stringParam(params, \"agentSessionId\"))\n}\n\nfunc (r *runtimeServer) openSession(id string, params map[string]json.RawMessage) (any, bool, error) {\n\tr.mu.Lock()\n\tif _, exists := r.sessions[id]; exists {\n\t\tr.mu.Unlock()\n\t\treturn nil, false, fmt.Errorf(\"Agent session already exists: %s\", id)\n\t}\n\tif len(r.sessions) >= maxAgentSessions {\n\t\tr.mu.Unlock()\n\t\treturn nil, false, fmt.Errorf(\"Agent session limit reached: %d\", maxAgentSessions)\n\t}\n\tsession := &agentSession{state: newEtcd2Session()}\n\tr.sessions[id] = session\n\tr.mu.Unlock()\n\n\tif _, err := session.state.connect(params); err != nil {\n\t\tr.mu.Lock()\n\t\tdelete(r.sessions, id)\n\t\tr.mu.Unlock()\n\t\tsession.state.close()\n\t\treturn nil, false, err\n\t}\n\treturn map[string]bool{\"ok\": true}, false, nil\n}\n\nfunc (r *runtimeServer) session(id string) (*agentSession, error) {\n\tr.mu.RLock()\n\tsession := r.sessions[id]","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/etcd2-go/main.go#L216-L252","documentation":"openSession enforces maxAgentSessions: once the number of live sessions reaches the cap, new opens are rejected with this error. It is a deliberate resource guard so the runtime server cannot accumulate unbounded etcd2 sessions.","triggerScenarios":"Opening a new session when len(r.sessions) >= maxAgentSessions — typically after many sessions were opened without being closed, or in a test suite that opens sessions per test.","commonSituations":"Long-running agents leaking sessions on error paths, load tests hitting the cap, raising concurrency without raising the limit.","solutions":["Close idle/finished sessions with closeSession before opening new ones.","Increase maxAgentSessions if the workload legitimately needs more concurrent sessions.","Add leak detection in callers: ensure every openSession has a matching close in a finally/defer path."],"exampleFix":"// before\nopenSession(id, params) // cap reached, throws\n// after\nfor _, old := range staleSessionIDs { closeSession(old) }\nopenSession(id, params)","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"session, err := openSession(id, params)\nif err != nil && strings.Contains(err.Error(), \"limit reached\") {\n    evictOldestSession()\n    session, err = openSession(id, params)\n}","preventionTips":["Close sessions deterministically (defer/finally)","Monitor live session count against maxAgentSessions","Pool and reuse sessions instead of one per request"],"tags":["session","limit","resource-exhaustion"],"backgroundTag":"resource-limit-exceeded","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"}