nginx/nginx · error
NGX_LOG_CRIT
NGX_LOG_CRIT
Error message
%s \"%s\" failed
What it means
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.
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
Example fix
# before - $server_id resolves to a directory that was never created access_log /var/log/nginx/$server_id/stream.log main; # after - pre-create the tree for every possible value (provisioning step) # mkdir -p /var/log/nginx/s1 /var/log/nginx/s2 && chown nginx:nginx /var/log/nginx/s1 /var/log/nginx/s2 access_log /var/log/nginx/$server_id/stream.log main;
Defensive patterns
Strategy: validation
Validate before calling
# before reload: prove the worker user can create files under every dynamic log dir sudo -u nginx bash -c 'mkdir -p /var/log/nginx/dyn && touch /var/log/nginx/dyn/.probe && rm /var/log/nginx/dyn/.probe' # and confirm fd headroom for open_log_file_cache ulimit -n; ls /proc/$(pgrep -o nginx)/fd | wc -l
Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of nginx/nginx@3f6f7824d4 (2026-08-22).
Data as JSON: /api/errors/b92e6796362d76c4.
Report an issue: GitHub.
Appendix: source
Thrown at src/stream/ngx_stream_log_module.c:473
lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
of.log = 1;
of.valid = lscf->open_file_cache_valid;
of.min_uses = lscf->open_file_cache_min_uses;
of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
if (ngx_open_cached_file(lscf->open_file_cache, &log, &of,
s->connection->pool)
!= NGX_OK)
{
if (of.err == 0) {
/* simulate successful logging */
return len;
}
ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno,
"%s \"%s\" failed", of.failed, log.data);
/* simulate successful logging */
return len;
}
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
"stream log #%d", of.fd);
n = ngx_write_fd(of.fd, buf, len);
return n;
}
#if (NGX_ZLIB)
static ssize_t
ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,View on GitHub (pinned to 3f6f7824d4)