{"record":{"id":"e8c2f77a3654e981","repo":"PrefectHQ/fastmcp","slug":"max-cache-size-must-be-non-negative-got-max-size","errorCode":null,"errorMessage":"max_cache_size must be non-negative, got {max_size}","messagePattern":"max_cache_size must be non-negative, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/utilities/token_cache.py","lineNumber":82,"sourceCode":"        *,\n        ttl_seconds: int | None = None,\n        max_size: int | None = None,\n    ) -> None:\n        \"\"\"Initialise the cache.\n\n        Args:\n            ttl_seconds: How long cached entries remain valid, in seconds.\n                ``None`` or ``0`` disables caching entirely.\n            max_size: Upper bound on the number of entries.  When the limit is\n                reached, expired entries are swept first; if still full the\n                oldest entry is evicted.  Defaults to 10 000.\n        \"\"\"\n        if ttl_seconds is not None and ttl_seconds < 0:\n            raise ValueError(\n                f\"cache_ttl_seconds must be non-negative, got {ttl_seconds}\"\n            )\n        if max_size is not None and max_size < 0:\n            raise ValueError(f\"max_cache_size must be non-negative, got {max_size}\")\n        self._ttl = ttl_seconds or 0\n        self._max_size = max_size if max_size is not None else DEFAULT_MAX_CACHE_SIZE\n        self._entries: dict[str, _CacheEntry] = {}\n        self._last_cleanup = time.monotonic()\n\n    @property\n    def enabled(self) -> bool:\n        \"\"\"Return whether caching is active.\"\"\"\n        return self._ttl > 0 and self._max_size > 0\n\n    # -- public API ----------------------------------------------------------\n\n    def get(self, token: str) -> tuple[bool, AccessToken | None]:\n        \"\"\"Look up a cached verification result.\n\n        Returns:\n            ``(True, AccessToken)`` on a cache hit, ``(False, None)`` on a miss\n            or when caching is disabled.  The returned ``AccessToken`` is a deep","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/utilities/token_cache.py#L64-L100","documentation":"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.","triggerScenarios":"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.","commonSituations":"Config typo ('-1000' instead of '1000'); unbounded growth attempts using a sentinel negative value instead of None; arithmetic on sizes that underflowed.","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"],"exampleFix":"// before\nTokenCache(max_size=-1000)\n// after\nTokenCache(max_size=1000)  # or max_size=None for default","handlingStrategy":"validation","validationCode":"def safe_token_cache(max_size=None, ttl_seconds=None):\n    if max_size is not None and max_size < 0:\n        max_size = None  # fall back to library default\n    return TokenCache(ttl_seconds=ttl_seconds, max_size=max_size)","typeGuard":"def is_valid_size(v) -> bool:\n    return v is None or (isinstance(v, int) and v >= 0)","tryCatchPattern":"try:\n    cache = TokenCache(max_size=size)\nexcept ValueError as e:\n    logger.warning(\"Bad max_size: %s; using default\", e)\n    cache = TokenCache(max_size=None)","preventionTips":["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"],"tags":["validation","configuration","valueerror"],"backgroundTag":"invalid-parameter-value","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}