{"record":{"id":"515bf2ee50fb079a","repo":"usestrix/strix","slug":"no-target-set-add-a-target-first","errorCode":null,"errorMessage":"No target set. Add a target first.","messagePattern":"No target set\\. Add a target first\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"strix/interface/tui/backend/controller.py","lineNumber":318,"sourceCode":"        # A bare prompt launches optimistically, like a coding agent: it skips\n        # the network model preflight and surfaces any model error live. A named\n        # target keeps the preflight so a real scan does not commit blind.\n        verify = payload.get(\"verify\", True)\n        if not isinstance(verify, bool):\n            raise TypeError(\"verify must be a boolean\")\n        # Launching with no target mounts the working directory, so it requires\n        # the user's explicit confirmation rather than happening silently.\n        mount_working_dir = payload.get(\"mount_working_dir\", False)\n        if not isinstance(mount_working_dir, bool):\n            raise TypeError(\"mount_working_dir must be a boolean\")\n        model = (load_settings().llm.model or \"\").strip()\n        if not model:\n            raise ValueError(\"No model configured. Set STRIX_LLM first.\")\n        if self._on_start is None:\n            raise RuntimeError(\"Scan start is unavailable\")\n        if not self.targets:\n            if not mount_working_dir:\n                raise ValueError(\"No target set. Add a target first.\")\n            # Mounting the working directory needs the user's confirmation, and\n            # that is asked in the live view. Enter it now and prepare nothing\n            # until the answer arrives, so declining leaves no run behind.\n            self.pending_workspace_mount = str(Path.cwd())\n            self._pending_verify = verify\n            self.setup_mode = False\n            self.scan_started = True\n            self.scan_state = \"preparing\"\n            return {\"started\": True}\n        await self._begin_scan(verify)\n        return {\"started\": True}\n\n    async def _begin_scan(self, verify: bool) -> None:\n        if self._on_start is None:\n            raise RuntimeError(\"Scan start is unavailable\")\n        self._start_in_progress = True\n        try:\n            await self._on_start(verify)","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/interface/tui/backend/controller.py#L300-L336","documentation":"Raised by _start (strix/interface/tui/backend/controller.py:318) when setup.start arrives with no targets registered and mount_working_dir is false. Strix can scan target-free by mounting the current working directory, but that mounts user files into the sandbox, so it requires the explicit mount_working_dir=true opt-in plus a live-view confirmation; without either, start is refused with this ValueError.","triggerScenarios":"Typing only a prompt in the TUI and pressing start before adding a target; frontend dropping the targets list on a state reset; sending {\"mount_working_dir\": false} with zero targets.","commonSituations":"Users expecting a bare prompt to run against nothing; UI bugs clearing self.targets; drivers that never call setup.add_target.","solutions":["Add a target first: setup.add_target with a valid target string, then setup.start.","Or intentionally scan the workspace: send setup.start with {\"mount_working_dir\": true} and approve the confirmation that the live view asks for.","If targets vanished unexpectedly, check for frontend state resets and re-add before starting."],"exampleFix":"# before\nawait controller.handle(\"setup.start\", {})   # no targets, no mount opt-in\n\n# after\nawait controller.handle(\"setup.add_target\", {\"target\": \"https://example.com\"})\nawait controller.handle(\"setup.start\", {})","handlingStrategy":"validation","validationCode":"if not controller.targets and not payload.get(\"mount_working_dir\", False):\n    print('add a target (setup.add_target) or opt into workspace mount first')","typeGuard":"def start_preconditions_met(controller, payload: dict) -> bool:\n    return bool(controller.targets) or payload.get(\"mount_working_dir\") is True","tryCatchPattern":"try:\n    await controller.handle(\"setup.start\", payload)\nexcept ValueError as exc:\n    if 'No target set' in str(exc):\n        await controller.handle(\"setup.add_target\", {\"target\": default_target})\n        await controller.handle(\"setup.start\", payload)\n    else:\n        raise","preventionTips":["Disable the start button until targets is non-empty or the mount toggle is on.","Remember workspace mounts need explicit user confirmation in the live view."],"tags":["tui","target","workspace-mount","validation"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}