PrefectHQ/fastmcp · error · ValueError
cache_ttl must be a positive integer, got {cache_ttl}
Error message
cache_ttl must be a positive integer, got {cache_ttl} What it means
build_cache_hints validates the FastMCP constructor's cache_ttl argument (seconds) used to emit SEP-2549 client-side cache hints. A non-positive TTL (zero or negative) cannot produce a meaningful cache lifetime, so the server refuses to start rather than silently emitting an inert or invalid hint. The TTL is converted to milliseconds for the wire (ttl_ms = cache_ttl * 1000).
Source
Thrown at fastmcp_slim/fastmcp/server/caching.py:56
`cache_ttl` is meaningless (the client gates caching on the presence of a
TTL) and is rejected rather than silently ignored.
Returns `None` when no hint is set, or a map applying the same hint to every
SDK-cacheable method otherwise.
Raises:
ValueError: If `cache_ttl` is not positive, or if `cache_scope` is set
without `cache_ttl`.
"""
if cache_ttl is None:
if cache_scope is not None:
raise ValueError(
"cache_scope requires cache_ttl; a scope without a TTL does not "
"enable caching"
)
return None
if cache_ttl <= 0:
raise ValueError(f"cache_ttl must be a positive integer, got {cache_ttl}")
hint = CacheHint(ttl_ms=cache_ttl * 1000, scope=cache_scope or "private")
return dict.fromkeys(get_args(CacheableMethod), hint)
View on GitHub (pinned to 1f02114297)
Solutions
- Pass a positive integer for cache_ttl (seconds), e.g. cache_ttl=60.
- To disable caching, omit cache_ttl entirely (pass None), not 0.
- If the value comes from config/env, coerce and validate before constructing FastMCP: ttl = int(raw) if raw else None.
- Note cache_scope cannot be given without cache_ttl; set both together or neither.
Example fix
// before
mcp = FastMCP("srv", cache_ttl=0, cache_scope="private")
// after
mcp = FastMCP("srv", cache_ttl=300, cache_scope="private")
# or disable: mcp = FastMCP("srv") Defensive patterns
Strategy: validation
Validate before calling
if cache_ttl is not None and (not isinstance(cache_ttl, int) or cache_ttl <= 0):
raise ValueError(f"cache_ttl must be a positive integer, got {cache_ttl!r}") Try / catch
try:
mcp = FastMCP("srv", cache_ttl=cfg.ttl, cache_scope=cfg.scope)
except ValueError as e:
logging.error("bad cache config: %s", e)
mcp = FastMCP("srv") # caching disabled Prevention
- Treat 0/"" from config as 'unset' and map to None before constructing FastMCP.
- Validate TTL-bearing config at startup with a schema (pydantic) using PositiveInt | None.
- Remember cache_scope requires cache_ttl; validate them as a pair.
When it happens
Trigger: Passing cache_ttl=0, cache_ttl<0, or a non-integer (e.g. 1.5) to FastMCP(..., cache_ttl=...). The check runs in build_cache_hints, called from FastMCP.__init__, so any construction with such a value raises immediately.
Common situations: Copy-pasted config where the TTL was left at a placeholder 0; unit tests probing invalid input; config-driven servers where a YAML/env value of 0 or -1 means 'disabled' to the author but is passed straight through as a number instead of None.
Understand the failure class
Background: "Invalid configuration value" and "Unsupported/Unknown setting value" errors: why libraries reject your config strings, numbers, and types — this error's family across 30 libraries.
Related errors
- Cannot resolve tool reference: {fn!r}
- Cannot determine tool name for {fn!r}
- File {name!r} not found. Available: {available}
- File {f.get('name', '?')!r} exceeds max size ({_format_size(
- ClientGroup requires at least one client
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/643352a3c16108b9.
Report an issue: GitHub.