{"id":"98132f6e50dd6201","repo":"aio-libs/aiohttp","slug":"gunicorn-s-style-options-in-form-of-name-s-are","errorCode":null,"errorMessage":"Gunicorn's style options in form of `%(name)s` are not supported for the log formatting. Please use aiohttp's format specification to configure access log formatting: http://docs.aiohttp.org/en/stable/logging.html#format-specification","messagePattern":"Gunicorn's style options in form of `(.+?)` are not supported for the log formatting\\. Please use aiohttp's format specification to configure access log formatting: http://docs\\.aiohttp\\.org/en/stable/logging\\.html#format-specification","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/worker.py","lineNumber":238,"sourceCode":"        See ssl.SSLSocket.__init__ for more details.\n        \"\"\"\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n\n        ctx = ssl.SSLContext(cfg.ssl_version)\n        ctx.load_cert_chain(cfg.certfile, cfg.keyfile)\n        ctx.verify_mode = cfg.cert_reqs\n        if cfg.ca_certs:\n            ctx.load_verify_locations(cfg.ca_certs)\n        if cfg.ciphers:\n            ctx.set_ciphers(cfg.ciphers)\n        return ctx\n\n    def _get_valid_log_format(self, source_format: str) -> str:\n        if source_format == self.DEFAULT_GUNICORN_LOG_FORMAT:\n            return self.DEFAULT_AIOHTTP_LOG_FORMAT\n        elif re.search(r\"%\\([^\\)]+\\)\", source_format):\n            raise ValueError(\n                \"Gunicorn's style options in form of `%(name)s` are not \"\n                \"supported for the log formatting. Please use aiohttp's \"\n                \"format specification to configure access log formatting: \"\n                \"http://docs.aiohttp.org/en/stable/logging.html\"\n                \"#format-specification\"\n            )\n        else:\n            return source_format\n\n\nclass GunicornUVLoopWebWorker(GunicornWebWorker):\n    def init_process(self) -> None:\n        import uvloop\n\n        asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())\n\n        super().init_process()\n","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/worker.py#L220-L256","documentation":"Raised by GunicornWebWorker._get_valid_log_format() as a ValueError when the access_log_format string contains Gunicorn-style named placeholders like `%(name)s`. aiohttp's AccessLogger uses its own format specification (positional `%s` and `{name}` style), not Gunicorn's `%(name)s` dictionary interpolation, so such formats are rejected at worker startup.","triggerScenarios":"Setting gunicorn's `access_log_format` to a string containing a `%(...)s` pattern (e.g. gunicorn's default `%(h)s %(l)s ...`) while using the aiohttp GunicornWebWorker. The regex search at aiohttp/worker.py:237 detects the pattern and raises.","commonSituations":"Copying a Gunicorn access log format from another project into the aiohttp worker config; relying on gunicorn's default format which the worker remaps automatically only when it exactly equals DEFAULT_GUNICORN_LOG_FORMAT; mixing gunicorn and aiohttp logging docs.","solutions":["Use aiohttp's format spec: positional `%s` for fixed fields and `{header_name}` / `{client_ip}` etc. See the logging docs link in the error.","If you want gunicorn's default behavior, leave access_log_format unset so it matches DEFAULT_GUNICORN_LOG_FORMAT and is auto-converted to aiohttp's DEFAULT_AIOHTTP_LOG_FORMAT.","Convert any `%(h)s` style tokens to the equivalent aiohttp `{client_ip}` / `%s` fields."],"exampleFix":"# before (gunicorn.cfg)\naccess_log_format = '%(h)s %(l)s %(t)s \"%(r)s\" %(s)s %(b)s \"%(f)s\" \"%(a)s\"'\n\n# after (aiohttp format spec)\naccess_log_format = '%a %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\"'","handlingStrategy":"validation","validationCode":"import re\n\ndef validate_log_format(fmt: str) -> str:\n    if re.search(r\"%\\([^\\)]+\\)\", fmt):\n        raise ValueError(\"use aiohttp format spec, not gunicorn %(name)s\")\n    return fmt","typeGuard":"import re\n\ndef is_aiohttp_log_format(fmt: str) -> bool:\n    return not re.search(r\"%\\([^\\)]+\\)\", fmt)","tryCatchPattern":null,"preventionTips":["Use aiohttp's access log format spec (%s positional, {name} fields), not gunicorn's %(name)s.","Leave access_log_format unset to get the auto-converted default.","Test the worker startup with the configured format in a staging env."],"tags":["gunicorn","worker","logging","config"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}