PrefectHQ/fastmcp · error · ValueError
max_cache_size must be non-negative, got {max_size}
Error message
max_cache_size must be non-negative, got {max_size} What it means
The TokenCache constructor validates its max_size parameter and raises ValueError when a negative number is passed. A negative capacity cannot bound the cache, so the library rejects it eagerly. Omit the parameter to use the default (10,000 entries) or pass None explicitly.
Source
Thrown at fastmcp_slim/fastmcp/utilities/token_cache.py:82
*,
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.
Returns:
``(True, AccessToken)`` on a cache hit, ``(False, None)`` on a miss
or when caching is disabled. The returned ``AccessToken`` is a deepView on GitHub (pinned to 1f02114297)
Solutions
- Set max_size to a non-negative integer
- Pass None (or omit) to use the default max cache size
- Fix the config/env source producing the negative number
Example fix
// before TokenCache(max_size=-1000) // after TokenCache(max_size=1000) # or max_size=None for default
Defensive patterns
Strategy: validation
Validate before calling
def safe_token_cache(max_size=None, ttl_seconds=None):
if max_size is not None and max_size < 0:
max_size = None # fall back to library default
return TokenCache(ttl_seconds=ttl_seconds, max_size=max_size) Type guard
def is_valid_size(v) -> bool:
return v is None or (isinstance(v, int) and v >= 0) Try / catch
try:
cache = TokenCache(max_size=size)
except ValueError as e:
logger.warning("Bad max_size: %s; using default", e)
cache = TokenCache(max_size=None) Prevention
- Treat None as the default-capacity sentinel, not negative numbers
- Validate size values parsed from config/env before use
- Test cache construction with your real config values
When it happens
Trigger: Constructing the token cache with max_size < 0, e.g. TokenCache(max_size=-1), or supplying a signed config value that parses to a negative int.
Common situations: Config typo ('-1000' instead of '1000'); unbounded growth attempts using a sentinel negative value instead of None; arithmetic on sizes that underflowed.
Related errors
- cache_ttl_seconds must be non-negative, got {ttl_seconds}
- 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/e8c2f77a3654e981.
Report an issue: GitHub.