Skip to content

[Bug]: Docker dashboard WebSocket /monitor/ws 500s — HTTP-only token_dep applied to the WS route (TypeError: _principal() missing 'request') #2060

Description

@rwb-truelime

crawl4ai version

0.9.0 (Docker server). Also present on develop — see below.

Summary

The monitor dashboard (/dashboard) never connects. Its WebSocket to /monitor/ws fails immediately; the browser console loops WebSocket connection to 'ws://<host>/monitor/ws' failed / WebSocket closed, and the header stays on Reconnecting…. The server returns HTTP 500 on the WS upgrade — even on a correctly authenticated request.

Root cause

deploy/docker/server.py includes the monitor router with a router-level dependency:

app.include_router(monitor_router, dependencies=[Depends(token_dep)])

token_dep is HTTP-only — deploy/docker/auth.py:

def get_token_dependency(config: Dict):
    def _principal(request: Request) -> Optional[Dict]:
        return get_principal(request)
    return _principal

Because the dependency is attached at the router level, it is applied to every route in the router, including the @router.websocket("/ws") endpoint. On a WebSocket scope FastAPI cannot inject request: Request, so _principal() is called with no arguments:

TypeError: get_token_dependency.<locals>._principal() missing 1 required positional argument: 'request'

...which surfaces as a 500 and the WS never upgrades. Note the WS handler itself declares no Depends and its own docstring says auth is handled by the middleware:

@router.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    # Auth is enforced by the AuthGateMiddleware (outermost ASGI layer) ...
    # No bespoke check here.
    await websocket.accept()

So the router-level token_dep is both broken for WS and redundant (authentication is already enforced by AuthGateMiddleware, which is also what populates request.state.principal that require_admin reads).

Traceback

File ".../fastapi/dependencies/utils.py", line 680, in solve_dependencies
File ".../starlette/concurrency.py", line 34, in run_in_threadpool
...
TypeError: get_token_dependency.<locals>._principal() missing 1 required positional argument: 'request'

Steps to reproduce

  1. Run the 0.9.0 Docker server with CRAWL4AI_API_TOKEN set.
  2. Open /dashboard (send the token however your deployment allows — e.g. reverse-proxy header injection).
  3. The dashboard shows Reconnecting…; the server logs the TypeError above on each /monitor/ws attempt (HTTP 500).

(There is a second, independent bug on this same route: prometheus_fastapi_instrumentator crashing on FastAPI's _IncludedRouter — reported in #2025 — which must also be resolved for the WS to work. This issue is specifically about the token_dep-on-WS TypeError.)

Fix

Drop the router-level dependency (auth stays enforced by AuthGateMiddleware; the destructive /monitor/actions/* and /monitor/stats/reset routes keep their own Depends(require_admin)):

-app.include_router(monitor_router, dependencies=[Depends(token_dep)])
+app.include_router(monitor_router)

(Alternatively, make the auth dependency WebSocket-aware, e.g. accept websocket: WebSocket in addition to request: Request — but since the middleware already gates the route, removing the redundant dependency is simplest.)

Verified with the change: /monitor/ws upgrades (101 Switching Protocols) and streams the expected JSON (health, requests, browsers, timeline, janitor, errors, timestamp); an unauthenticated WS is still rejected by AuthGateMiddleware; the admin action routes still require an admin credential.

Still present on develop

develop has the same line — app.include_router(monitor_router, dependencies=[Depends(token_dep)]) (server.py, ~line 486) with _principal(request: Request) (auth.py, ~line 130) — so this is not fixed there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ⚙️ In-progressIssues, Features requests that are in Progress🐞 BugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions