nginx/nginx · error

NGX_LOG_ALERT

NGX_LOG_ALERT

Error message

sendfile() reported that \"%s\" was truncated at %O

What it means

In ngx_freebsd_sendfile_chain(): FreeBSD sendfile() returned success (rc >= 0) but reported zero bytes sent, which means file_pos is at or beyond EOF - the file shrank after nginx opened it and cached its size. nginx logs this ALERT and returns NGX_CHAIN_ERROR, aborting the connection's output; the client connection is typically closed mid-response.

Source

Thrown at src/os/unix/ngx_freebsd_sendfile_chain.c:229

                }

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
                               "sendfile() sent only %O bytes", sent);

            /*
             * sendfile() in FreeBSD 3.x-4.x may return value >= 0
             * on success, although only 0 is documented
             */

            } else if (rc >= 0 && sent == 0) {

                /*
                 * if rc is OK and sent equal to zero, then someone
                 * has truncated the file, so the offset became beyond
                 * the end of the file
                 */

                ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                         "sendfile() reported that \"%s\" was truncated at %O",
                         file->file->name.data, file->file_pos);

                return NGX_CHAIN_ERROR;
            }

            ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
                           "sendfile: %d, @%O %O:%uz",
                           rc, file->file_pos, sent, file_size + header.size);

        } else {
            n = ngx_writev(c, &header);

            if (n == NGX_ERROR) {
                return NGX_CHAIN_ERROR;
            }

            sent = (n == NGX_AGAIN) ? 0 : n;

View on GitHub (pinned to 3f6f7824d4)

Solutions

  1. Replace files atomically: write new content to a temp name in the same directory and rename() it over the old path - never truncate a file nginx may be serving
  2. If logrotate is the culprit, drop copytruncate and use create/rename plus postrotate `nginx -s reopen`
  3. As a diagnostic or temporary workaround set `sendfile off;` so nginx read()s the file (still serves correct data, at a performance cost)
  4. Flush open_file_cache (or lower open_file_cache_valid) if stale sizes keep reproducing the alert

Example fix

# before (logrotate)
/var/www/files/*.bin {
  copytruncate
  weekly
}
# after
/var/www/files/*.bin {
  weekly
  postrotate
    [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
  endscript
}
Defensive patterns

Strategy: validation

Validate before calling

struct stat st;
if (fstat(file->file->fd, &st) == 0 && file->file_pos > st.st_size) {
    /* file shrank under us: re-open instead of sendfile()ing past EOF */
}

Type guard

static ngx_int_t
file_not_truncated(ngx_file_t *f, off_t pos)
{
    struct stat  st;
    return fstat(f->fd, &st) == 0 && pos <= st.st_size ? NGX_OK : NGX_ERROR;
}

Try / catch

NGX_CHAIN_ERROR from the FreeBSD sendfile path aborts the connection's output chain: propagate it (close the connection, count the truncation), and fix the writer. Guard downstream by restat-ing size before sendfile and reopening when it shrank; ops-side, replace truncation with atomic rename.

Prevention

When it happens

Trigger: A served static file is truncated after open: logrotate with copytruncate on files being downloaded, shell `> file` redirection or truncate -s 0 by deploy scripts, in-place rewrites by applications, or NFS re-exports changing size while open_file_cache holds stale metadata.

Common situations: Download/log files managed by logrotate copytruncate; deployment pipelines that truncate-and-rewrite instead of atomic rename; shared storage where another host rewrites the file; stale open_file_cache entries after upstream file changes.

Related errors


AI-assisted analysis of nginx/nginx@3f6f7824d4 (2026-08-22). Data as JSON: /api/errors/a1103932f05f0a36. Report an issue: GitHub.