{"record":{"id":"0d6673ec40392cf0","repo":"agentscope-ai/agentscope","slug":"session-session-id-r-already-has-an-active-chat","errorCode":null,"errorMessage":"Session {session_id!r} already has an active chat run in this process.","messagePattern":"Session (.+?) already has an active chat run in this process\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/agentscope/app/_manager/_chat_run_registry.py","lineNumber":74,"sourceCode":"                Optional task name passed through to\n                :func:`asyncio.create_task`. Defaults to\n                ``f\"chat-run:{session_id}\"``.\n\n        Returns:\n            `asyncio.Task`:\n                The created task. Callers normally do not need to keep\n                the reference — the registry holds it for the task's\n                lifetime.\n\n        Raises:\n            `RuntimeError`:\n                When a non-finished task is already registered for\n                ``session_id``. Callers are expected to coordinate via\n                the distributed session lock before spawning.\n        \"\"\"\n        existing = self._tasks.get(session_id)\n        if existing is not None and not existing.done():\n            raise RuntimeError(\n                f\"Session {session_id!r} already has an active chat run \"\n                \"in this process.\",\n            )\n\n        task = asyncio.create_task(\n            coro,\n            name=name or f\"chat-run:{session_id}\",\n        )\n        self._tasks[session_id] = task\n\n        def _cleanup(t: asyncio.Task) -> None:\n            # Only remove the entry if it still points at this task —\n            # a fresh spawn for the same sid may have replaced it.\n            if self._tasks.get(session_id) is t:\n                self._tasks.pop(session_id, None)\n\n        task.add_done_callback(_cleanup)\n        return task","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/app/_manager/_chat_run_registry.py#L56-L92","documentation":"The per-process ChatRunRegistry refuses to spawn a second asyncio task for a session that already has a live (not done) chat run. It enforces one active run per session per process; callers are expected to coordinate via the distributed session lock before spawning.","triggerScenarios":"Calling chat()/dispatch twice for the same session_id before the first run finishes, or when a previous task was never awaited/cancelled and is still pending.","commonSituations":"Double-clicking a send button where the frontend fires two chat requests; a webhook and a user action racing for the same session; retrying a request while the previous run is still executing; missing distributed session lock when running the app behind multiple workers.","solutions":["Wait for or cancel the existing run before starting a new one for the session","Acquire the distributed session lock around spawn so concurrent workers serialize per-session runs","On the client side, disable/queue new submissions while a run is active (surface 409)","If the old run is stuck, cancel it via the interrupt/cancel API then retry"],"exampleFix":"# before\nresp = requests.post(f\"/chat\", json={...})  # second click -> 409\n\n# after\nasync with session_lock(request.session_id):\n    existing = registry.get(request.session_id)\n    if existing and not existing.done():\n        raise BusyError(\"session busy\")\n    await registry.spawn(request.session_id, coro)","handlingStrategy":"try-catch","validationCode":"existing = registry._tasks.get(session_id)\nbusy = existing is not None and not existing.done()","typeGuard":null,"tryCatchPattern":"try:\n    await registry.spawn(session_id, coro)\nexcept RuntimeError as e:\n    if \"already has an active chat run\" in str(e):\n        await interrupt(session_id)  # or wait for completion","preventionTips":["Hold the distributed session lock around per-session spawns","Expose run status so callers can check before spawning","Implement client-side submission locking per session"],"tags":["agentscope","chat-run","concurrency","session","conflict"],"backgroundTag":"duplicate-active-request","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}