{"record":{"id":"b92e6796362d76c4","repo":"nginx/nginx","slug":"ngx-log-crit-b92e67","errorCode":"NGX_LOG_CRIT","errorMessage":"%s \\\"%s\\\" failed","messagePattern":"(.+?) \\\\\"(.+?)\\\\\" failed","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/ngx_stream_log_module.c","lineNumber":473,"sourceCode":"    lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);\n\n    ngx_memzero(&of, sizeof(ngx_open_file_info_t));\n\n    of.log = 1;\n    of.valid = lscf->open_file_cache_valid;\n    of.min_uses = lscf->open_file_cache_min_uses;\n    of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;\n\n    if (ngx_open_cached_file(lscf->open_file_cache, &log, &of,\n                             s->connection->pool)\n        != NGX_OK)\n    {\n        if (of.err == 0) {\n            /* simulate successful logging */\n            return len;\n        }\n\n        ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno,\n                      \"%s \\\"%s\\\" failed\", of.failed, log.data);\n        /* simulate successful logging */\n        return len;\n    }\n\n    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,\n                   \"stream log #%d\", of.fd);\n\n    n = ngx_write_fd(of.fd, buf, len);\n\n    return n;\n}\n\n\n#if (NGX_ZLIB)\n\nstatic ssize_t\nngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/nginx/nginx/blob/3f6f7824d4e2eb1ac37dec76683d525ac0ff521c/src/stream/ngx_stream_log_module.c#L455-L491","documentation":"Thrown by the stream access_log writer when a log file whose name contains runtime variables (dynamic log names) cannot be opened. ngx_stream_log_script_write() resolves the variable name per session and calls ngx_open_cached_file(); on a real errno it logs this CRIT message with the failing operation (of.failed, typically 'open()') and the resolved path. The log line is then silently dropped ('simulate successful logging'); proxying continues, only the log record is lost.","triggerScenarios":"access_log with variables in the filename where the resolved directory does not exist (nginx never creates intermediate directories), the worker user lacks write permission on the directory, a symlink target is missing when open_log_file_cache is on, the resolved name exceeds NAME_MAX (ENAMETOOLONG), or open files are exhausted (EMFILE/ENFILE) with open_log_file_cache max=N.","commonSituations":"Per-client or per-listener log files like /logs/$server_id.log where the target directory was never created; containers or hardened hosts running workers as 'nobody' with restrictive permissions; SELinux/AppArmor denying writes to custom log paths; low ulimit -n combined with open_log_file_cache on busy stream endpoints.","solutions":["Create the missing directory and give the worker user write access: mkdir -p /logs/dir && chown nginx /logs/dir","Fix permissions or SELinux context so the worker can create files there; verify with: sudo -u nginx touch /logs/dir/.probe","Check that the variables in the filename resolve to sane values (no empty segments, no path-hostile characters, no over-long names)","If EMFILE/ENFILE: raise worker_rlimit_nofile (or systemd LimitNOFILE) or enlarge open_log_file_cache inactive timeouts","Watch error.log for this CRIT message after deploy; it only appears at runtime, not during nginx -t"],"exampleFix":"# before - $server_id resolves to a directory that was never created\naccess_log /var/log/nginx/$server_id/stream.log main;\n\n# after - pre-create the tree for every possible value (provisioning step)\n#   mkdir -p /var/log/nginx/s1 /var/log/nginx/s2 && chown nginx:nginx /var/log/nginx/s1 /var/log/nginx/s2\naccess_log /var/log/nginx/$server_id/stream.log main;","handlingStrategy":"validation","validationCode":"# before reload: prove the worker user can create files under every dynamic log dir\nsudo -u nginx bash -c 'mkdir -p /var/log/nginx/dyn && touch /var/log/nginx/dyn/.probe && rm /var/log/nginx/dyn/.probe'\n# and confirm fd headroom for open_log_file_cache\nulimit -n; ls /proc/$(pgrep -o nginx)/fd | wc -l","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-create every directory a variable log path can resolve to, in provisioning (Ansible/Terraform), not at runtime - nginx never mkdirs","Remember nginx -t validates syntax only; it does not touch the filesystem targets, so run a writability probe as the worker user in your deploy pipeline","Monitor error.log for 'stream' + CRIT 'failed' and alert; dropped records are silent otherwise","Cap open_log_file_cache max and raise worker_rlimit_nofile on hosts with many dynamic log files"],"tags":["nginx","stream","logging","filesystem","permissions"],"backgroundTag":"log-file-open-failed","analyzedSha":"3f6f7824d4e2eb1ac37dec76683d525ac0ff521c","analyzedAt":"2026-08-22T03:09:46.447Z","contentChangedAt":"2026-08-22T03:09:46.447Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}