{"record":{"id":"ba5508736761d443","repo":"PrefectHQ/fastmcp","slug":"interval-ms-must-be-positive","errorCode":null,"errorMessage":"interval_ms must be positive","messagePattern":"interval_ms must be positive","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/middleware/ping.py","lineNumber":39,"sourceCode":"        from fastmcp import FastMCP\n        from fastmcp.server.middleware import PingMiddleware\n\n        mcp = FastMCP(\"MyServer\")\n        mcp.add_middleware(PingMiddleware(interval_ms=5000))\n        ```\n    \"\"\"\n\n    def __init__(self, interval_ms: int = 30000):\n        \"\"\"Initialize ping middleware.\n\n        Args:\n            interval_ms: Interval between pings in milliseconds (default: 30000)\n\n        Raises:\n            ValueError: If interval_ms is not positive\n        \"\"\"\n        if interval_ms <= 0:\n            raise ValueError(\"interval_ms must be positive\")\n        self.interval_ms = interval_ms\n        self._active_sessions: set[int] = set()\n        self._lock = anyio.Lock()\n\n    async def on_message(self, context: MiddlewareContext, call_next: CallNext) -> Any:\n        \"\"\"Start ping task on first message from a connection.\"\"\"\n        if (\n            context.fastmcp_context is None\n            or context.fastmcp_context.request_context is None\n        ):\n            return await call_next(context)\n\n        session = context.fastmcp_context.session\n        # SDK v2 constructs a ServerSession per request; the stable per-connection\n        # identity lives on the underlying Connection. Key the keepalive loop off\n        # it so one ping task runs for the whole connection and is torn down when\n        # the connection closes.\n        connection = getattr(session, \"_connection\", None)","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/middleware/ping.py#L21-L57","documentation":"A ValueError raised in the PingMiddleware constructor when interval_ms is zero or negative. The middleware pings active sessions on a timer, so a non-positive interval would spin or be meaningless; construction is rejected immediately.","triggerScenarios":"Instantiating PingMiddleware(interval_ms=0) or PingMiddleware(interval_ms=-100), e.g. from a computed or misconfigured config value (0 from an unset env var parsed as int).","commonSituations":"Environment variable or YAML config supplying 0 for the interval; arithmetic like ms = seconds * 1000 where seconds defaulted to 0; copying a sample config with a placeholder 0.","solutions":["Pass a positive interval_ms (default is 30000).","If the value comes from config/env, validate or clamp it before constructing the middleware."],"exampleFix":"// before\ninterval = int(os.getenv(\"PING_INTERVAL_MS\", \"0\"))\nmw = PingMiddleware(interval_ms=interval)  # ValueError\n\n// after\ninterval = max(int(os.getenv(\"PING_INTERVAL_MS\", \"30000\")), 1)\nmw = PingMiddleware(interval_ms=interval)","handlingStrategy":"validation","validationCode":"interval_ms = int(os.getenv(\"PING_INTERVAL_MS\", \"30000\"))\nassert interval_ms > 0, f\"PING_INTERVAL_MS must be positive, got {interval_ms}\"\nmw = PingMiddleware(interval_ms=interval_ms)","typeGuard":null,"tryCatchPattern":"try:\n    mw = PingMiddleware(interval_ms=interval_ms)\nexcept ValueError as e:\n    logging.warning(\"bad ping interval, using default: %s\", e)\n    mw = PingMiddleware()","preventionTips":["Never default interval config values to 0; use the library default (30000).","Clamp parsed env/config integers with max(value, 1).","Add a config schema check that rejects non-positive durations at load time.","Watch unit conversions (seconds→milliseconds) for zero-producing defaults."],"tags":["configuration","validation","middleware"],"backgroundTag":"invalid-parameter-value","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}