HKUDS/Vibe-Trading · error · HTTPException

mandate for {broker} has expired; re-authorize first

Error message

mandate for {broker} has expired; re-authorize first

What it means

HTTP 409 from the live-runner start endpoint: a mandate for the broker exists but mandate.expired is True. Mandates have a bounded validity window; an expired mandate cannot drive a runner and must be re-authorized before starting.

Source

Thrown at agent/src/api/live_routes.py:989

        if not broker_supports_live_runner(broker):
            raise HTTPException(
                status_code=400,
                detail=f"live runner is not supported for {broker}",
            )

        h = _host()
        tasks = h._runner_tasks

        existing = tasks.get(broker)
        if existing is not None and not existing.done():
            return {"broker": broker, "started": False, "already_running": True}

        mandate = h._active_mandate_state(broker)
        if mandate is None:
            raise HTTPException(status_code=409, detail=f"no committed mandate for {broker}")
        if mandate.expired:
            raise HTTPException(status_code=409, detail=f"mandate for {broker} has expired; re-authorize first")
        if halt_flag_set(broker=broker) or halt_flag_set(broker=None):
            raise HTTPException(status_code=409, detail="kill switch is tripped; resume before starting the runner")

        try:
            runner = h._build_live_runner(broker)
        except LiveRunnerUnavailable as exc:
            raise HTTPException(status_code=503, detail=str(exc)) from exc
        except Exception as exc:
            raise HTTPException(status_code=500, detail=f"could not construct runner: {exc}") from exc

        task = asyncio.ensure_future(h._drive_runner(runner))
        tasks[broker] = task
        task.add_done_callback(
            lambda t, b=broker: tasks.pop(b, None) if tasks.get(b) is t else None
        )

        h._emit_live_event(
            payload.session_id,

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Re-run the mandate authorization/commit flow for the broker to get a fresh, unexpired mandate, then retry start
  2. Check server clock sync (NTP) if the mandate should still be valid
  3. Consider requesting a longer mandate validity window when authorizing if expiries are frequent

Example fix

// before
POST /api/live/runner/start {"broker": "alpaca"}  // 409 mandate expired
// after
POST /api/live/mandate/commit {"broker": "alpaca", ...}
POST /api/live/runner/start {"broker": "alpaca"}
Defensive patterns

Strategy: retry

Validate before calling

m = get(f'/api/live/mandate/{broker}').json()
from datetime import datetime, timezone
if datetime.fromisoformat(m['expires_at']) < datetime.now(timezone.utc):
    commit_mandate(broker)  # re-authorize

Try / catch

catch 409 with 'has expired'; re-run authorization/commit, then retry start exactly once

Prevention

When it happens

Trigger: POST to start the runner for a broker whose committed mandate's expiry timestamp has passed — e.g. a long-lived runner restarted after the mandate TTL elapsed.

Common situations: Restarting runners after maintenance windows or downtime, long TTL gaps overnight, or clock skew between the mandate issuer and the API host causing premature expiry.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/f8461009a19d1e8d. Report an issue: GitHub.