ruvnet/RuView · error · HTTPException
Access denied to zone '{zone_id}'
Error message
Access denied to zone '{zone_id}' What it means
validate_zone_access raises 403 "Access denied to zone '<zone_id>'" when the authenticated user is not an admin, their zones list is non-empty, and the requested zone is not in it. Note the semantics: an empty zones list means 'no restriction' — denial only happens when a list exists and the zone is absent from it.
Source
Thrown at archive/v1/src/api/dependencies.py:204
)
# Check if zone is enabled
if not zone.enabled:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Zone '{zone_id}' is disabled"
)
# If authentication is enabled, check user access
if current_user:
# Admin users have access to all zones
if current_user.get("is_admin", False):
return zone_id
# Check user's zone permissions
user_zones = current_user.get("zones", [])
if user_zones and zone_id not in user_zones:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Access denied to zone '{zone_id}'"
)
return zone_id
# Router access dependencies
async def validate_router_access(
router_id: str,
current_user: Optional[Dict[str, Any]] = Depends(get_current_user)
) -> str:
"""Validate user access to a specific router."""
domain_config = get_domain_config()
# Check if router exists
router = domain_config.get_router(router_id)
if not router:View on GitHub (pinned to 4685618388)
Solutions
- Add the zone to the user's zones allowlist (or request access from an admin)
- Use an admin token, which bypasses the zone allowlist
- If the user should see all zones, clear their zones list (empty means unrestricted)
Defensive patterns
Strategy: validation
Validate before calling
# Check the token's zone allowlist before the call (empty list = unrestricted)
claims = jwt.decode(token, options={'verify_signature': False})
zones = claims.get('zones') or []
if zones and zone_id not in zones and not claims.get('is_admin'):
raise PermissionError(f'Token not scoped for zone {zone_id}')
client.get(f'/api/zones/{zone_id}/pose', headers=auth) Try / catch
try:
r = client.get(f'/api/zones/{zone_id}/pose', headers=auth)
r.raise_for_status()
except httpx.HTTPStatusError as e:
if e.response.status_code == 403 and 'Access denied' in e.response.text:
# scope problem: request access or switch to an allowed zone
switch_to_allowed_zone()
raise Prevention
- Update user zone allowlists whenever new zones are provisioned
- Decode and inspect the zones claim when troubleshooting 403s
- Remember empty zones list means unrestricted — explicit allowlists deny everything else
When it happens
Trigger: A user provisioned with zones=['beta'] calling a route for zone 'alpha'; scoped service accounts missing the newly added zone; stale tokens whose zones claim predates a zone addition.
Common situations: Onboarding a user without adding the new zone to their allowlist; per-zone tenancy enforcement; forgotten update of the user's zones after zone creation.
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
- Zone '{zone_id}' is disabled
- Access denied to router '{router_id}'
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/e33501d1e819658d.
Report an issue: GitHub.