{"record":{"id":"650b72fb0ef3b78f","repo":"python/cpython","slug":"ssl-shutdown-timeout-should-be-a-positive-number","errorCode":null,"errorMessage":"ssl_shutdown_timeout should be a positive number, got {ssl_shutdown_timeout}","messagePattern":"ssl_shutdown_timeout should be a positive number, got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/sslproto.py","lineNumber":290,"sourceCode":"                 call_connection_made=True,\n                 ssl_handshake_timeout=None,\n                 ssl_shutdown_timeout=None):\n        if ssl is None:\n            raise RuntimeError(\"stdlib ssl module not available\")\n\n        self._ssl_buffer = bytearray(self.max_size)\n        self._ssl_buffer_view = memoryview(self._ssl_buffer)\n\n        if ssl_handshake_timeout is None:\n            ssl_handshake_timeout = constants.SSL_HANDSHAKE_TIMEOUT\n        elif ssl_handshake_timeout <= 0:\n            raise ValueError(\n                f\"ssl_handshake_timeout should be a positive number, \"\n                f\"got {ssl_handshake_timeout}\")\n        if ssl_shutdown_timeout is None:\n            ssl_shutdown_timeout = constants.SSL_SHUTDOWN_TIMEOUT\n        elif ssl_shutdown_timeout <= 0:\n            raise ValueError(\n                f\"ssl_shutdown_timeout should be a positive number, \"\n                f\"got {ssl_shutdown_timeout}\")\n\n        if not sslcontext:\n            sslcontext = _create_transport_context(\n                server_side, server_hostname)\n\n        self._server_side = server_side\n        if server_hostname and not server_side:\n            self._server_hostname = server_hostname\n        else:\n            self._server_hostname = None\n        self._sslcontext = sslcontext\n        # SSL-specific extra info. More info are set when the handshake\n        # completes.\n        self._extra = dict(sslcontext=sslcontext)\n\n        # App data write buffering","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/sslproto.py#L272-L308","documentation":"Raised in _SSLProtocol.__init__ as ValueError when an explicitly supplied ssl_shutdown_timeout is <= 0 (and not None). This timeout bounds the TLS shutdown/close_notify exchange when the connection is torn down; non-positive values are rejected because the graceful-shutdown wait would be degenerate.","triggerScenarios":"Passing ssl_shutdown_timeout=0 or a negative value to the asyncio SSL entry points (loop.create_connection, create_server, start_server, start_tls) which forward it into _SSLProtocol.","commonSituations":"Mirroring ssl_handshake_timeout tuning and setting both to 0 intending 'no timeout'; env-driven config parsing empty values as 0; CI configs that clamp all timeouts to 0 for speed.","solutions":["Use a positive duration: ssl_shutdown_timeout=5.","Use None/omit the parameter for the default (constants.SSL_SHUTDOWN_TIMEOUT, 30s).","Sanitize numeric config inputs at load time, rejecting non-positive timeout values early with a clear message."],"exampleFix":"// before\nawait loop.create_connection(proto, 'h', 443, ssl=ctx, ssl_shutdown_timeout=0)\n# ValueError\n\n// after\nawait loop.create_connection(proto, 'h', 443, ssl=ctx, ssl_shutdown_timeout=5.0)","handlingStrategy":"validation","validationCode":"def shutdown_timeout(value):\n    if value is None:\n        return None  # asyncio default (30s)\n    value = float(value)\n    if value <= 0:\n        raise ValueError('ssl_shutdown_timeout must be > 0')\n    return value\n\nawait loop.create_connection(proto, 'h', 443, ssl=ctx,\n                              ssl_shutdown_timeout=shutdown_timeout(cfg))","typeGuard":"def is_positive_timeout(v) -> bool:\n    return v is None or (isinstance(v, (int, float)) and not isinstance(v, bool) and v > 0)","tryCatchPattern":"try:\n    await loop.create_connection(proto, 'h', 443, ssl=ctx, ssl_shutdown_timeout=t)\nexcept ValueError as e:\n    if 'ssl_shutdown_timeout' in str(e):\n        await loop.create_connection(proto, 'h', 443, ssl=ctx)\n    else:\n        raise","preventionTips":["Use None or a positive seconds value for ssl_shutdown_timeout.","Share one timeout validator for handshake and shutdown kwargs.","Reject non-positive values in config parsing with explicit errors."],"tags":["asyncio","ssl","timeout","shutdown","configuration"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}