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

  1. Add the zone to the user's zones allowlist (or request access from an admin)
  2. Use an admin token, which bypasses the zone allowlist
  3. 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

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

Related errors


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/e33501d1e819658d. Report an issue: GitHub.