usestrix/strix · warning · RuntimeError

Agent '{agent_id}' cannot be stopped while {status or 'unkno

Error message

Agent '{agent_id}' cannot be stopped while {status or 'unknown'}

What it means

Raised by _stop_agent when the agent exists but its current status is not in _STOPPABLE_AGENT_STATUSES = {'running', 'waiting', 'budget_paused'} (controller.py:36). Strix only allows graceful cancellation of agents that are actively working or paused; agents that already completed, failed, or were cancelled cannot be stopped again. The message interpolates the actual status (or 'unknown' when the status field is empty).

Source

Thrown at strix/interface/tui/backend/controller.py:392

                self.coordinator.send(
                    agent_id,
                    {"from": "user", "content": message, "type": "instruction"},
                ),
                self.scan_loop,
            )
            delivered = await asyncio.wrap_future(future)
        if not delivered:
            raise RuntimeError("Message could not be delivered")
        return {"sent": True}

    async def _stop_agent(self, payload: dict[str, Any]) -> dict[str, Any]:
        agent_id = self._required_string(payload, "agent_id")
        agent = self.live_view.agents.get(agent_id)
        if agent is None:
            raise ValueError(f"Unknown agent: {agent_id}")
        status = str(agent.get("status", ""))
        if status not in _STOPPABLE_AGENT_STATUSES:
            raise RuntimeError(f"Agent '{agent_id}' cannot be stopped while {status or 'unknown'}")
        if self.coordinator is None or self.scan_loop is None or self.scan_loop.is_closed():
            raise RuntimeError("Scan loop is not ready")
        if self.scan_loop is asyncio.get_running_loop():
            accepted = await self.coordinator.cancel_descendants_graceful(agent_id)
        else:
            future = asyncio.run_coroutine_threadsafe(
                self.coordinator.cancel_descendants_graceful(agent_id), self.scan_loop
            )
            accepted = await asyncio.wrap_future(future)
        if not accepted:
            raise RuntimeError(f"Agent '{agent_id}' is no longer active")
        return {"stopped": True}

    async def _open_viewer(self, _payload: dict[str, Any]) -> dict[str, Any]:
        if self.viewer_url:
            with contextlib.suppress(Exception):
                webbrowser.open(self.viewer_url)
            return {"status": "running", "url": self.viewer_url}

View on GitHub (pinned to 8551339130)

Solutions

  1. Check agent.get('status') is one of running/waiting/budget_paused before issuing stop
  2. Refresh live_view.agents and re-evaluate; if the agent already finished, no stop is needed
  3. Disable the stop control in the UI for non-stoppable statuses
  4. Treat 'completed'/'failed' agents as already stopped and remove them from actionable lists

Example fix

# before
await controller._stop_agent({"agent_id": aid})

# after
STOPPABLE = {"running", "waiting", "budget_paused"}
status = controller.live_view.agents.get(aid, {}).get("status", "")
if status in STOPPABLE:
    await controller._stop_agent({"agent_id": aid})
Defensive patterns

Strategy: validation

Validate before calling

STOPPABLE = {"running", "waiting", "budget_paused"}
status = controller.live_view.agents.get(aid, {}).get("status", "")
if status not in STOPPABLE:
    logging.info("agent %s already %s; no stop needed", aid, status or "unknown")
    return

Type guard

def agent_stoppable(agents: dict, aid: str) -> bool:
    return agents.get(aid, {}).get("status", "") in {"running", "waiting", "budget_paused"}

Try / catch

try:
    await controller._stop_agent({"agent_id": aid})
except RuntimeError as e:
    if "cannot be stopped while" in str(e):
        pass  # already finished/failed — treat as done
    else:
        raise

Prevention

When it happens

Trigger: Calling stop on an agent whose live_view status is e.g. 'completed', 'failed', 'cancelled', or missing/empty (renders as 'unknown'). Common double-click scenario: user hits stop right as the agent finishes.

Common situations: UI stop button not disabled for finished agents; racing a stop request with agent completion; stale agent row still showing in the panel; status field missing in custom agent snapshots.

Related errors


AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15). Data as JSON: /api/errors/f59ff38d301c73f4. Report an issue: GitHub.