ruvnet/RuView · error · RangeError
unsupported guidance topic: ${topic}
Error message
unsupported guidance topic: ${topic} What it means
The blanket 'except Exception' at auth.py:381 wraps the whole refresh_token body, converting every failure - including the inner AuthenticationError('User not found or inactive') raised a few lines above, since AuthenticationError subclasses Exception - into 'Token refresh failed'. The true cause is discarded (not even logged here), which makes diagnosis misleading.
Source
Thrown at harness/homecore/src/guidance.js:74
if (!options || typeof options !== 'object' || Array.isArray(options)) {
throw new TypeError('guidance options must be an object');
}
if (input.topic !== undefined && typeof input.topic !== 'string') {
throw new TypeError('guidance topic must be a string');
}
if (input.query !== undefined && typeof input.query !== 'string') {
throw new TypeError('guidance query must be a string');
}
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),View on GitHub (pinned to 4685618388)
Solutions
- Treat any 'Token refresh failed' as 're-login required': call login to get a fresh token
- Patch the handler to re-raise AuthenticationError before the generic except, and log the original exception: except AuthenticationError: raise / except Exception as e: logger.error(e)
- Verify settings.jwt_expire_hours and jwt_algorithm are set so token creation inside refresh cannot blow up
Example fix
# before (auth.py:381)
except Exception as e:
raise AuthenticationError("Token refresh failed")
# after
except AuthenticationError:
raise
except Exception as e:
logger.error(f"Token refresh error: {e}")
raise AuthenticationError("Token refresh failed") Defensive patterns
Strategy: fallback
Validate before calling
def refresh_preconditions_ok(settings) -> bool:
"""create_access_token inside refresh needs these settings present."""
return (
getattr(settings, "jwt_expire_hours", None) is not None
and bool(getattr(settings, "secret_key", None))
and bool(getattr(settings, "jwt_algorithm", None))
) Try / catch
try:
tokens = await middleware.refresh_token(token)
except AuthenticationError as e:
if str(e) == "Token refresh failed":
# opaque mask: any cause -> fall back to full login
tokens = await middleware.login(username, password)
else:
raise Prevention
- Patch the handler to re-raise AuthenticationError before the generic except
- Log the original exception in the catch-all
- Clients: treat refresh failure as login-required, never retry the same token
When it happens
Trigger: Refreshing an expired or invalid token (inner verify_token raises AuthenticationError('Invalid token'), then masked); refreshing for a missing/inactive user ('User not found or inactive' masked); create_access_token failing because settings.jwt_expire_hours is None and the timedelta arithmetic raises TypeError.
Common situations: Client refresh racing token expiry: expired token produces 'Token refresh failed' instead of a clearer invalid-token message; misconfigured settings surfacing as opaque auth errors; debugging wasted because the inner message never reaches logs.
Related errors
- guidance topic must be a string
- guidance repoRoot must be a string or null
- 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/87230f8e3d4e9fec.
Report an issue: GitHub.