usestrix/strix · error · ValueError
Unknown agent: {agent_id}
Error message
Unknown agent: {agent_id} What it means
Raised by _stop_agent when the supplied agent_id does not exist in live_view.agents, the controller's live snapshot of agents in the current scan. It is a ValueError (bad input) rather than a state error: the id itself is wrong before any stop machinery is consulted. Ids are exact strings, so any mismatch in casing, prefix, or staleness triggers it.
Source
Thrown at strix/interface/tui/backend/controller.py:389
)
else:
future = asyncio.run_coroutine_threadsafe(
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:View on GitHub (pinned to 8551339130)
Solutions
- Re-read controller.live_view.agents and use an id that currently exists
- Print the available agent ids on failure so the caller can self-correct
- In scripts, always discover ids from the live view at call time instead of hardcoding
- Verify the id matches exactly (case-sensitive, full string)
Example fix
# before
await controller._stop_agent({"agent_id": "scanner"})
# after
agents = controller.live_view.agents
if "scanner" not in agents:
raise SystemExit(f"unknown agent; available: {sorted(agents)}")
await controller._stop_agent({"agent_id": "scanner"}) Defensive patterns
Strategy: validation
Validate before calling
if agent_id not in controller.live_view.agents:
raise KeyError(f"unknown agent {agent_id}; known: {sorted(controller.live_view.agents)}") Type guard
def is_known_agent(agents: dict, aid: str) -> bool:
return aid in agents Try / catch
try:
await controller._stop_agent({"agent_id": aid})
except ValueError as e:
if str(e).startswith("Unknown agent"):
aid = pick_from(controller.live_view.agents) # refresh id
else:
raise Prevention
- Discover agent ids from live_view at call time, never hardcode
- Print available ids on lookup failure for quick self-correction
- In scripts, re-fetch the agent list after any spawn/finish event
When it happens
Trigger: Calling stop-agent with an id copied from a previous scan, a truncated id, or an id assembled by the frontend (e.g. missing a numeric suffix). The lookup is live_view.agents.get(agent_id) returning None.
Common situations: UI list is stale after agents spawned or finished; user pastes an agent id from an older run; automated scripts iterating a cached agent list; typo in hand-written ids.
Related errors
- Agent '{agent_id}' cannot be stopped while {status or 'unkno
- {name} must be a non-empty string
- No target set. Add a target first.
- approved must be a boolean
- Agent '{agent_id}' is no longer active
AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15).
Data as JSON: /api/errors/5ab472a99251f757.
Report an issue: GitHub.