odysseus-dev/odysseus · warning · HTTPException

Workspace selection is admin-only

Error message

Workspace selection is admin-only

What it means

HTTP 403 from GET /vet: same admin gate as /browse. The vet endpoint validates a candidate workspace path (existence, sensitivity checks) on the host filesystem, which confirms path existence to the caller — hence admin-only. Non-admin users cannot pre-validate typed paths and must go through the normal (admin-controlled) workspace flow.

Source

Thrown at routes/workspace_routes.py:80

            "truncated": truncated,
            # Whether this directory may be bound as a workspace (filesystem
            # roots and sensitive dirs may be browsed through but not chosen).
            "selectable": vet_workspace(target) is not None,
        }

    @router.get("/vet")
    def vet(request: Request, path: str = Query(default="")):
        """Validate a workspace path without binding it.

        The UI calls this before persisting a manually typed path (/workspace
        set) so a typo, file path, deleted folder, sensitive dir, or filesystem
        root is rejected up front with the canonical path returned on success,
        instead of being stored client-side and silently dropped at chat time.
        Admin-gated like /browse: it confirms path existence on the host.
        """
        owner = get_current_user(request)
        if not owner_is_admin_or_single_user(owner):
            raise HTTPException(status_code=403, detail="Workspace selection is admin-only")
        from src.tool_execution import vet_workspace
        resolved = vet_workspace(path)
        return {"ok": resolved is not None, "path": resolved}

    return router

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Use an admin session for path vetting/selection
  2. Hide the manual path input for non-admins in the UI so /vet is never called
  3. Non-admins: accept the workspace assigned by the admin instead of a custom path
Defensive patterns

Strategy: type-guard

Validate before calling

if not owner_is_admin_or_single_user(get_current_user(request)):
    disable_manual_path_input()  # /vet is never called for non-admins

Type guard

def can_vet_workspace(user) -> bool:
    return owner_is_admin_or_single_user(user)

Try / catch

if resp.status_code == 403:
    fall_back_to_admin_set_workspace()

Prevention

When it happens

Trigger: A non-admin user's UI calling /vet before /workspace set with a manually typed path; automated scripts using a regular user's session cookie against the vet route.

Common situations: The settings page shows the path picker to non-admins in multi-user deployments; permission downgrades while the page stays open.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/f804c5e8742f578e. Report an issue: GitHub.