ruvnet/RuView · error · RangeError
guidance limit must be between 1 and 20
Error message
guidance limit must be between 1 and 20
What it means
The role check inside require_role's decorator (auth.py:406): check_permission returned False, meaning the authenticated user's roles list contains neither the required role nor the 'admin' super-role. The message interpolates the exact missing role, e.g. "Role 'admin' required".
Source
Thrown at harness/homecore/src/guidance.js:82
}
if (input.limit !== undefined && (typeof input.limit !== 'number' || !Number.isFinite(input.limit))) {
throw new TypeError('guidance limit must be a finite number');
}
if (options.repoRoot !== undefined && options.repoRoot !== null && typeof options.repoRoot !== 'string') {
throw new TypeError('guidance repoRoot must be a string or null');
}
const topic = input.topic === undefined ? 'overview' : input.topic;
if (!GUIDANCE_TOPICS.includes(topic)) {
throw new RangeError(`unsupported guidance topic: ${topic}`);
}
const query = input.query === undefined ? '' : input.query.trim();
if (query && (query.length < 2 || query.length > 500)) {
throw new RangeError('guidance query must contain 2..500 characters');
}
const rawLimit = input.limit === undefined ? 20 : input.limit;
if (rawLimit < 1 || rawLimit > 20) {
throw new RangeError('guidance limit must be between 1 and 20');
}
const limit = Math.floor(rawLimit);
const wanted = tokenize(query);
const candidates = CAPABILITIES
.filter((capability) => topic === 'overview' || capability.topics.includes(topic))
.map((capability, order) => ({
capability,
order,
score: scoreCapability(capability, wanted),
}))
.filter(({ score }) => score > 0)
.sort((a, b) => b.score - a.score || a.order - b.order)
.slice(0, limit)
.map(({ capability }) => ({
...capability,
topics: [...capability.topics],
sources: [...capability.sources],View on GitHub (pinned to 4685618388)
Solutions
- Grant the role: update the user record so roles includes the required value, then log in again so the JWT carries it
- Check for case/whitespace mismatches between the provisioned role string and required_role
- If the role was just granted but the token is old, refresh or re-login to mint a token with current roles
Example fix
# before
user_manager.create_user('alice', 'a@b.c', pw) # roles default to ['user']
# after
user_manager.create_user('alice', 'a@b.c', pw, roles=['admin']) # then re-login Defensive patterns
Strategy: type-guard
Validate before calling
def user_has_role(user_info: dict, required_role: str) -> bool:
"""Mirrors check_permission including the admin bypass."""
roles = user_info.get("roles", []) if user_info else []
return "admin" in roles or required_role in roles Type guard
from typing import Any, Dict
def can_access(user_info: Any, required_role: str) -> bool:
"""Narrow an optional user dict to 'authorized for required_role'."""
if not isinstance(user_info, dict):
return False
roles = user_info.get("roles") or []
return isinstance(roles, list) and ("admin" in roles or required_role in roles) Try / catch
from src.middleware.auth import AuthorizationError
try:
result = await protected_handler(request)
except AuthorizationError as e:
if "required" in str(e): # "Role 'X' required"
raise HTTPException(403, detail=str(e))
raise Prevention
- Re-login after role grants so the JWT roles claim is current
- Use exact lowercase role strings everywhere
- Check can_access() client-side to hide unauthorized actions
When it happens
Trigger: A user created with default roles ['user'] calling a @require_role('admin') route; calling a 'sensor' or 'operator' endpoint with an account provisioned without that role; roles claim in the JWT stale because the token predates a role grant.
Common situations: Fresh registrations defaulting to ['user'] hitting admin tooling; role granted in the store but old unexpired token still carries the old roles claim; role-name typos between provisioning and the decorator ('Admin' vs 'admin' - check is case-sensitive).
Related errors
- prompt must be a non-empty string
- guidance query must contain 2..500 characters
- brain line ${index + 1}: exceeds 16 KiB
- brain line ${index + 1}: ${error.message}
- brain line ${index + 1}: ${errors.join('; ')}
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/26cf50769c4af578.
Report an issue: GitHub.