{"record":{"id":"ae528f7565adaea5","repo":"ruvnet/RuView","slug":"router-router-id-is-disabled","errorCode":null,"errorMessage":"Router '{router_id}' is disabled","messagePattern":"Router '(.+?)' is disabled","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"archive/v1/src/api/dependencies.py","lineNumber":230,"sourceCode":"# Router access dependencies\nasync def validate_router_access(\n    router_id: str,\n    current_user: Optional[Dict[str, Any]] = Depends(get_current_user)\n) -> str:\n    \"\"\"Validate user access to a specific router.\"\"\"\n    domain_config = get_domain_config()\n    \n    # Check if router exists\n    router = domain_config.get_router(router_id)\n    if not router:\n        raise HTTPException(\n            status_code=status.HTTP_404_NOT_FOUND,\n            detail=f\"Router '{router_id}' not found\"\n        )\n    \n    # Check if router is enabled\n    if not router.enabled:\n        raise HTTPException(\n            status_code=status.HTTP_403_FORBIDDEN,\n            detail=f\"Router '{router_id}' is disabled\"\n        )\n    \n    # If authentication is enabled, check user access\n    if current_user:\n        # Admin users have access to all routers\n        if current_user.get(\"is_admin\", False):\n            return router_id\n        \n        # Check user's router permissions\n        user_routers = current_user.get(\"routers\", [])\n        if user_routers and router_id not in user_routers:\n            raise HTTPException(\n                status_code=status.HTTP_403_FORBIDDEN,\n                detail=f\"Access denied to router '{router_id}'\"\n            )\n    ","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/archive/v1/src/api/dependencies.py#L212-L248","documentation":"validate_router_access raises 403 \"Router '<router_id>' is disabled\" when the router exists in domain configuration but has enabled=False. Existence was confirmed first; this is a per-router administrative kill switch.","triggerScenarios":"A router node deliberately disabled (maintenance, decommissioned hardware) still receiving API traffic; config edits flipping enabled accidentally.","commonSituations":"Taking an ESP32 node offline while dashboards keep polling it; staged hardware rollouts with disabled flags; config merge mistakes.","solutions":["Set enabled=True for the router in the domain configuration and reload","Update clients to stop referencing the disabled router","Surface disabled vs missing distinctly in client error handling"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Only target enabled routers\nrouters = client.get('/api/routers', headers=auth).json()\nenabled = [r['id'] for r in routers if r.get('enabled', True)]\nif router_id not in enabled:\n    skip_or_alert(router_id)","typeGuard":null,"tryCatchPattern":"try:\n    r = client.get(f'/api/routers/{router_id}', headers=auth)\n    r.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 403 and 'disabled' in e.response.text:\n        mark_router_offline(router_id)  # maintenance state; stop polling\n    raise","preventionTips":["Reflect the enabled flag in device dashboards","Treat router-disabled 403 as expected during maintenance windows","Alert on disabled-but-polled routers to find stale clients"],"tags":["routers","http-403","configuration","python"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}