{"record":{"id":"f8461009a19d1e8d","repo":"HKUDS/Vibe-Trading","slug":"mandate-for-broker-has-expired-re-authorize-fir","errorCode":null,"errorMessage":"mandate for {broker} has expired; re-authorize first","messagePattern":"mandate for (.+?) has expired; re-authorize first","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"error","filePath":"agent/src/api/live_routes.py","lineNumber":989,"sourceCode":"\n        if not broker_supports_live_runner(broker):\n            raise HTTPException(\n                status_code=400,\n                detail=f\"live runner is not supported for {broker}\",\n            )\n\n        h = _host()\n        tasks = h._runner_tasks\n\n        existing = tasks.get(broker)\n        if existing is not None and not existing.done():\n            return {\"broker\": broker, \"started\": False, \"already_running\": True}\n\n        mandate = h._active_mandate_state(broker)\n        if mandate is None:\n            raise HTTPException(status_code=409, detail=f\"no committed mandate for {broker}\")\n        if mandate.expired:\n            raise HTTPException(status_code=409, detail=f\"mandate for {broker} has expired; re-authorize first\")\n        if halt_flag_set(broker=broker) or halt_flag_set(broker=None):\n            raise HTTPException(status_code=409, detail=\"kill switch is tripped; resume before starting the runner\")\n\n        try:\n            runner = h._build_live_runner(broker)\n        except LiveRunnerUnavailable as exc:\n            raise HTTPException(status_code=503, detail=str(exc)) from exc\n        except Exception as exc:\n            raise HTTPException(status_code=500, detail=f\"could not construct runner: {exc}\") from exc\n\n        task = asyncio.ensure_future(h._drive_runner(runner))\n        tasks[broker] = task\n        task.add_done_callback(\n            lambda t, b=broker: tasks.pop(b, None) if tasks.get(b) is t else None\n        )\n\n        h._emit_live_event(\n            payload.session_id,","sourceCodeStart":971,"sourceCodeEnd":1007,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/api/live_routes.py#L971-L1007","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-run the mandate authorization/commit flow for the broker to get a fresh, unexpired mandate, then retry start","Check server clock sync (NTP) if the mandate should still be valid","Consider requesting a longer mandate validity window when authorizing if expiries are frequent"],"exampleFix":"// before\nPOST /api/live/runner/start {\"broker\": \"alpaca\"}  // 409 mandate expired\n// after\nPOST /api/live/mandate/commit {\"broker\": \"alpaca\", ...}\nPOST /api/live/runner/start {\"broker\": \"alpaca\"}","handlingStrategy":"retry","validationCode":"m = get(f'/api/live/mandate/{broker}').json()\nfrom datetime import datetime, timezone\nif datetime.fromisoformat(m['expires_at']) < datetime.now(timezone.utc):\n    commit_mandate(broker)  # re-authorize","typeGuard":null,"tryCatchPattern":"catch 409 with 'has expired'; re-run authorization/commit, then retry start exactly once","preventionTips":["Track mandate expiry client-side and re-authorize proactively before TTL","Keep server clocks NTP-synced"],"tags":["live-trading","mandate","expiry","http-409"],"backgroundTag":"authorization-expired","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}