PrefectHQ/fastmcp · error · ValueError
cache_ttl_seconds must be non-negative, got {ttl_seconds}
Error message
cache_ttl_seconds must be non-negative, got {ttl_seconds} What it means
The TokenCache constructor validates its cache_ttl_seconds parameter at init time and raises ValueError when a negative number is passed. A negative TTL is meaningless (entries would be instantly expired), so the library rejects it eagerly rather than silently misbehaving. Pass None or 0 to disable caching instead.
Source
Thrown at fastmcp_slim/fastmcp/utilities/token_cache.py:78
"""
def __init__(
self,
*,
ttl_seconds: int | None = None,
max_size: int | None = None,
) -> None:
"""Initialise the cache.
Args:
ttl_seconds: How long cached entries remain valid, in seconds.
``None`` or ``0`` disables caching entirely.
max_size: Upper bound on the number of entries. When the limit is
reached, expired entries are swept first; if still full the
oldest entry is evicted. Defaults to 10 000.
"""
if ttl_seconds is not None and ttl_seconds < 0:
raise ValueError(
f"cache_ttl_seconds must be non-negative, got {ttl_seconds}"
)
if max_size is not None and max_size < 0:
raise ValueError(f"max_cache_size must be non-negative, got {max_size}")
self._ttl = ttl_seconds or 0
self._max_size = max_size if max_size is not None else DEFAULT_MAX_CACHE_SIZE
self._entries: dict[str, _CacheEntry] = {}
self._last_cleanup = time.monotonic()
@property
def enabled(self) -> bool:
"""Return whether caching is active."""
return self._ttl > 0 and self._max_size > 0
# -- public API ----------------------------------------------------------
def get(self, token: str) -> tuple[bool, AccessToken | None]:
"""Look up a cached verification result.View on GitHub (pinned to 1f02114297)
Solutions
- Set cache_ttl_seconds to a non-negative number (0 or None disables caching)
- Fix the config/env value source so it parses to a positive integer
- Check any TTL arithmetic (e.g. expiry - now) and clamp with max(0, delta)
Example fix
// before TokenCache(ttl_seconds=-60) // after TokenCache(ttl_seconds=60) # or 0/None to disable
Defensive patterns
Strategy: validation
Validate before calling
def ensure_valid_cache_config(ttl_seconds=None, max_size=None):
if ttl_seconds is not None and ttl_seconds < 0:
raise ValueError(f"cache_ttl_seconds must be non-negative, got {ttl_seconds}")
if max_size is not None and max_size < 0:
raise ValueError(f"max_cache_size must be non-negative, got {max_size}")
return TokenCache(ttl_seconds=ttl_seconds, max_size=max_size) Type guard
def is_valid_ttl(v) -> bool:
return v is None or (isinstance(v, (int, float)) and v >= 0) Try / catch
try:
cache = TokenCache(ttl_seconds=ttl)
except ValueError as e:
logger.warning("Bad cache config: %s; disabling cache", e)
cache = TokenCache(ttl_seconds=None) Prevention
- Validate config values at load time, before they reach the library
- Use None (not a negative sentinel) to express 'unlimited/disabled'
- Clamp computed TTLs: ttl = max(0, expiry - now)
- Add a unit test asserting negative inputs raise ValueError
When it happens
Trigger: Constructing the token cache (directly or via a provider that wires one up) with cache_ttl_seconds set to a negative value, e.g. TokenCache(ttl_seconds=-60) or a config/env value like TTL=-1 parsed into an int.
Common situations: Config files or environment variables holding signed integers where a '-' was typed by mistake; computing a TTL via subtraction (now - later) that went negative; copying a tuning example and flipping the sign.
Related errors
- max_cache_size must be non-negative, got {max_size}
- mode must be 'legacy', 'auto', or one of {list(MODERN_PROTOC
- a custom cache store requires CacheConfig.target_id for Fast
- ClientGroup requires at least one client
- Protocol mode for server {name!r} must be a string
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/ffad25c56ee2f10e.
Report an issue: GitHub.