ruvnet/RuView · error · HTTPException
Access denied to router '{router_id}'
Error message
Access denied to router '{router_id}' What it means
validate_router_access raises 403 "Access denied to router '<router_id>'" when the authenticated user is not an admin, their routers list is non-empty, and the requested router is not in it. As with zones, an empty routers list means unrestricted; denial requires a non-empty list that excludes the router.
Source
Thrown at archive/v1/src/api/dependencies.py:244
)
# Check if router is enabled
if not router.enabled:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Router '{router_id}' is disabled"
)
# If authentication is enabled, check user access
if current_user:
# Admin users have access to all routers
if current_user.get("is_admin", False):
return router_id
# Check user's router permissions
user_routers = current_user.get("routers", [])
if user_routers and router_id not in user_routers:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Access denied to router '{router_id}'"
)
return router_id
# Service health dependencies
async def check_service_health(
request: Request,
service_name: str
) -> bool:
"""Check if a service is healthy."""
try:
if service_name == "pose":
service = getattr(request.app.state, 'pose_service', None)
elif service_name == "stream":
service = getattr(request.app.state, 'stream_service', None)View on GitHub (pinned to 4685618388)
Solutions
- Add the router to the user's routers allowlist (or have an admin do it)
- Use an admin token, which bypasses the router allowlist
- If the user should access all routers, clear their routers list
Defensive patterns
Strategy: validation
Validate before calling
# Check the token's router allowlist before the call (empty list = unrestricted)
claims = jwt.decode(token, options={'verify_signature': False})
routers = claims.get('routers') or []
if routers and router_id not in routers and not claims.get('is_admin'):
raise PermissionError(f'Token not scoped for router {router_id}') Try / catch
try:
r = client.get(f'/api/routers/{router_id}', headers=auth)
r.raise_for_status()
except httpx.HTTPStatusError as e:
if e.response.status_code == 403 and 'Access denied' in e.response.text:
request_router_access(router_id)
raise Prevention
- Update router allowlists when new hardware is provisioned
- Decode the routers claim when debugging 403s
- Remember an empty routers list means unrestricted access
When it happens
Trigger: A user provisioned with routers=['node-a'] calling a route for 'node-b'; scoped service accounts whose allowlist predates a newly added router; stale tokens after router provisioning changes.
Common situations: Per-node access scoping for field technicians; adding hardware without updating user allowlists; token claims drifting from current permissions.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Inactive user
- Admin privileges required
- Permission '{permission}' required
- Access denied to zone '{zone_id}'
- Router '{router_id}' is disabled
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/eb26afb951745c7d.
Report an issue: GitHub.