t8y2/dbx · error

agent session limit reached: {MAX_AGENT_SESSIONS}

Error message

agent session limit reached: {MAX_AGENT_SESSIONS}

What it means

open_session enforces a cap of MAX_AGENT_SESSIONS concurrently open sessions using an OwnedSemaphorePermit per session (the permit is stored in AgentSession::_slot and released when the session is closed/dropped). try_acquire_owned() fails when all permits are held, so the runtime refuses to open another session with this error. It is classified as a 'resource' error, retryable=true, session_disposition 'keep'.

Source

Thrown at agents/drivers/tdengine/src/runtime.rs:239

            }
        }
    }

    async fn open_session(&self, id: &str, params: ConnectParams) -> Result<()> {
        if id.trim().is_empty() {
            bail!("agentSessionId is required");
        }
        {
            let sessions = self.sessions.read().await;
            if sessions.contains_key(id) {
                bail!("agent session already exists: {id}");
            }
        }
        let slot = self
            .session_slots
            .clone()
            .try_acquire_owned()
            .map_err(|_| anyhow!("agent session limit reached: {MAX_AGENT_SESSIONS}"))?;
        let mut driver = TdengineDriver::new();
        driver.connect(params).await?;
        let session = Arc::new(AgentSession {
            driver: Mutex::new(driver),
            active: StdMutex::new(None),
            next_operation_id: AtomicU64::new(1),
            _slot: slot,
        });
        let mut sessions = self.sessions.write().await;
        if sessions.contains_key(id) {
            bail!("agent session already exists: {id}");
        }
        sessions.insert(id.to_string(), session);
        Ok(())
    }

    async fn session(&self, id: &str) -> Result<Arc<AgentSession>> {
        self.sessions.read().await.get(id).cloned().ok_or_else(|| anyhow!("agent session not found: {id}"))

View on GitHub (pinned to c0390bff16)

Solutions

  1. Call close_session (or disconnect) for sessions no longer in use before opening new ones — permits are freed when sessions close
  2. Reuse an existing session id: the error is retryable and sessions are kept, so retry after closing one, or reconnect to a live agentSessionId
  3. Restart the agent process (or send 'shutdown') to clear all leaked sessions and free all slots
  4. Audit the client for session leaks — every open_session must have a matching close_session, including on error paths

Example fix

// before: leak — new session per query, never closed
for q in queries {
  send({"method":"open_session","params":{"agentSessionId": format!("s-{}", n), ...}});
  run(q);
}
// after: close each session when done
for q in queries {
  send(open_session(id));
  run(q);
  send({"method":"close_session","params":{"agentSessionId": id}});
}
Defensive patterns

Strategy: validation

Validate before calling

const MAX_SESSIONS = 8; // must not exceed the agent's MAX_AGENT_SESSIONS
const openSessions = new Set();
function canOpenSession(id) {
  return !openSessions.has(id) && openSessions.size < MAX_SESSIONS;
}
if (!canOpenSession(id)) throw new Error("close an existing session before opening a new one");

Type guard

function isSessionLimitError(res) {
  return res?.error?.data?.category === "resource"
    && /session limit reached/i.test(res.error?.message ?? "");
}

Try / catch

try {
  await sendRpc({ method: "open_session", params });
} catch (res) {
  if (isSessionLimitError(res)) {
    const oldest = oldestOpenSession();
    await sendRpc({ method: "close_session", params: { agentSessionId: oldest } });
    await sendRpc({ method: "open_session", params }); // retryable=true, safe to retry
  } else { throw res; }
}

Prevention

When it happens

Trigger: Calling open_session (or the legacy 'connect' method, which routes to open_session under LEGACY_SESSION_ID) when MAX_AGENT_SESSIONS sessions are already open and not closed; leaked sessions from prior connections that were never closed with close_session/disconnect.

Common situations: A client that opens a new agentSessionId per query without closing previous ones; app reconnect loops creating sessions after network blips while old sessions linger; a driver upgrade/restart of the host that lost track of session ids but left the agent process running; multi-connection tooling exceeding the configured session budget.

Related errors


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