usestrix/strix · error · TypeError

approved must be a boolean

Error message

approved must be a boolean

What it means

Raised by the TUI controller's _confirm_mount handler when the payload sent to confirm (or decline) a pending working-directory mount does not carry a strict boolean 'approved' field. Strix requires an explicit true/false decision because the mount confirmation is a security-relevant consent gate; any ambiguous value (string "true", 1, null, missing key) is rejected with a TypeError. This guards against frontend/IPC serialization bugs that would silently coerce the user's choice.

Source

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

        if self._on_start is None:
            raise RuntimeError("Scan start is unavailable")
        self._start_in_progress = True
        try:
            await self._on_start(verify)
        finally:
            self._start_in_progress = False
        self.setup_mode = False
        self.scan_started = True
        self.scan_state = "running"

    async def _confirm_mount(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Answer the pending working-directory mount asked for in the live view."""
        mount = self.pending_workspace_mount
        if mount is None:
            raise RuntimeError("No mount confirmation is pending")
        approved = payload.get("approved")
        if not isinstance(approved, bool):
            raise TypeError("approved must be a boolean")
        self.pending_workspace_mount = None
        # Declining skips the mount, it does not abandon the scan. The prompt is
        # the whole of the input either way; the working directory is only an
        # extra the agent may look at, so the run goes ahead without one.
        self.workspace_mount = mount if approved else None
        await self._begin_scan(self._pending_verify)
        return {"approved": approved}

    async def _send_message(self, payload: dict[str, Any]) -> dict[str, Any]:
        agent_id = self._required_string(payload, "agent_id")
        message = self._required_string(payload, "message")
        if self.coordinator is None:
            raise RuntimeError("Agent coordinator is unavailable")
        if self.scan_loop is None or self.scan_loop.is_closed():
            raise RuntimeError("Scan loop is not ready")
        self.live_view.record_user_message(agent_id, message)
        if self.scan_loop is asyncio.get_running_loop():
            delivered = await self.coordinator.send(

View on GitHub (pinned to 8551339130)

Solutions

  1. Send {"approved": true} or {"approved": false} as a real JSON boolean, not a string or integer
  2. Check the message schema in strix/interface/tui/backend/controller.py _confirm_mount and match the expected payload exactly
  3. In test harnesses, use json.loads('{"approved": true}') rather than hand-built dicts with coerced values
  4. If wrapping the controller, validate with isinstance(payload.get('approved'), bool) before dispatch

Example fix

// before
await controller.dispatch("confirm_mount", {"approved": "true"})

// after
await controller.dispatch("confirm_mount", {"approved": True})
Defensive patterns

Strategy: type-guard

Validate before calling

approved = payload.get("approved")
if not isinstance(approved, bool):
    raise ValueError("payload['approved'] must be a JSON boolean")

Type guard

def is_confirm_payload(p: dict) -> bool:
    return isinstance(p.get("approved"), bool)

Try / catch

try:
    await controller.dispatch("confirm_mount", payload)
except TypeError as e:
    if "approved must be a boolean" in str(e):
        fix_payload_types()  # coerce/repair then resend once

Prevention

When it happens

Trigger: Calling the controller's confirm-mount command with payload {"approved": "true"}, {"approved": 1}, {"approved": null}, or omitting the key entirely while pending_workspace_mount is set. Typically happens when a custom TUI frontend or test harness JSON-encodes the flag as a non-bool type.

Common situations: Custom Bubble Tea/IPC clients serializing booleans as strings; test fixtures using 0/1 integers; payload builders that default missing values to None; protocol changes after upgrading Strix where the confirm message shape changed.

Related errors


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