usestrix/strix · error · RuntimeError
Scan start is unavailable
Error message
Scan start is unavailable
What it means
Raised by _start (strix/interface/tui/backend/controller.py:315) when the controller was constructed without an _on_start callback. The callback is the wiring that actually launches the scan; without it the TUI shell can collect setup input but cannot begin a run, so pressing start raises RuntimeError. This is an internal wiring/dependency-injection defect, not a user input error.
Source
Thrown at strix/interface/tui/backend/controller.py:315
async def _start(self, payload: dict[str, Any]) -> dict[str, Any]:
if self.scan_started or self._start_in_progress:
raise RuntimeError("Scan is already starting or running")
# A bare prompt launches optimistically, like a coding agent: it skips
# the network model preflight and surfaces any model error live. A named
# target keeps the preflight so a real scan does not commit blind.
verify = payload.get("verify", True)
if not isinstance(verify, bool):
raise TypeError("verify must be a boolean")
# Launching with no target mounts the working directory, so it requires
# the user's explicit confirmation rather than happening silently.
mount_working_dir = payload.get("mount_working_dir", False)
if not isinstance(mount_working_dir, bool):
raise TypeError("mount_working_dir must be a boolean")
model = (load_settings().llm.model or "").strip()
if not model:
raise ValueError("No model configured. Set STRIX_LLM first.")
if self._on_start is None:
raise RuntimeError("Scan start is unavailable")
if not self.targets:
if not mount_working_dir:
raise ValueError("No target set. Add a target first.")
# Mounting the working directory needs the user's confirmation, and
# that is asked in the live view. Enter it now and prepare nothing
# until the answer arrives, so declining leaves no run behind.
self.pending_workspace_mount = str(Path.cwd())
self._pending_verify = verify
self.setup_mode = False
self.scan_started = True
self.scan_state = "preparing"
return {"started": True}
await self._begin_scan(verify)
return {"started": True}
async def _begin_scan(self, verify: bool) -> None:
if self._on_start is None:
raise RuntimeError("Scan start is unavailable")View on GitHub (pinned to 8551339130)
Solutions
- Pass an async on_start callback when constructing the controller (see how the production TUI runtime wires it).
- In tests, inject a stub: controller = Controller(on_start=fake_start) before sending setup.start.
- Check the constructor signature for your Strix version — the parameter may have been renamed/added.
Example fix
# before
controller = SetupController() # no on_start
await controller.handle("setup.start", {}) # RuntimeError: Scan start is unavailable
# after
async def fake_start(verify: bool) -> None: ...
controller = SetupController(on_start=fake_start)
await controller.handle("setup.start", {}) Defensive patterns
Strategy: type-guard
Validate before calling
if getattr(controller, '_on_start', None) is None:
raise RuntimeError('controller has no on_start; wire the launcher before use') Type guard
def controller_can_start(controller) -> bool:
return getattr(controller, '_on_start', None) is not None Try / catch
try:
await controller.handle("setup.start", {})
except RuntimeError as exc:
if 'Scan start is unavailable' in str(exc):
raise RuntimeError('embedding bug: construct controller with on_start=...') from exc
raise Prevention
- Always inject an async on_start when constructing the controller (production TUI does).
- In tests, pass a stub launcher.
- Assert the wiring in a smoke test for custom hosts.
When it happens
Trigger: Instantiating SetupController (or equivalent) directly in tests or embedding code without passing the on_start coroutine; a TUI composition refactor that forgot to inject the launcher; version skew where the constructor signature changed.
Common situations: Writing automated tests for the controller without a fake on_start; embedding the backend controller in a custom host app; partial upgrades where an old caller no longer supplies the callback.
Related errors
- The interactive interface could not start: {exc}
- Unknown command: {command}
- instruction must be a string
- Scan is already starting or running
- verify must be a boolean
AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15).
Data as JSON: /api/errors/d84c55412aab6b11.
Report an issue: GitHub.