vectordotdev/vector · error · io::Error

UnexpectedEof

UnexpectedEof

Error message

EOF reached

What it means

The file source's fingerprinter reads the first N lines (up to `fingerprint.lines`, after `ignored_header_bytes`) of a file to compute its identity checksum, using `fingerprinter_read_until` to fill a fixed buffer. A read returning `Ok(0)` before the buffer is full means end-of-file was hit prematurely, and it is surfaced as `UnexpectedEof` ("EOF reached"). This typically means the file is too short for the configured fingerprint window (including gzip inputs whose decompressed head is smaller than needed).

Source

Thrown at lib/file-source-common/src/fingerprinter.rs:256

                };
                // For scenarios other than UnexpectedEOF, remove the path from the small files map.
                known_small_files.remove(&path.to_path_buf());
            })
            .ok()
            .flatten()
    }
}

async fn fingerprinter_read_until(
    mut r: impl AsyncRead + Unpin + Send,
    delim: u8,
    mut count: usize,
    mut buf: &mut [u8],
) -> Result<usize> {
    let mut total_read = 0;
    'main: while !buf.is_empty() {
        let read = match r.read(buf).await {
            Ok(0) => return Err(std::io::Error::new(ErrorKind::UnexpectedEof, "EOF reached")),
            Ok(n) => n,
            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };

        for (pos, &c) in buf[..read].iter().enumerate() {
            if c == delim {
                if count <= 1 {
                    total_read += pos + 1;
                    break 'main;
                } else {
                    count -= 1;
                }
            }
        }
        total_read += read;
        buf = &mut buf[read..];
    }

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Keep `fingerprint.lines` at 1 (default) unless every matched file is guaranteed longer.
  2. Tighten the glob (`exclude_files`, or match `*.log` only) so transient empty/partial files being written are not fingerprinted.
  3. If identical first lines across files force a bigger window, ensure `fingerprint.lines` stays below the smallest real file's line count, or switch `fingerprint.strategy` to `devino` (inode-based, no content read).
  4. Verify `ignored_header_bytes` is smaller than the files being matched.

Example fix

# before
sources:
  logs:
    type: file
    include: ["/var/log/app/*"]
    fingerprint:
      lines: 5
# short files (<5 lines) hit UnexpectedEof

# after
sources:
  logs:
    type: file
    include: ["/var/log/app/*.log"]
    fingerprint:
      lines: 1
Defensive patterns

Strategy: validation

Validate before calling

# Config-side: keep fingerprint window within the smallest file
fingerprint:
  strategy: checksum
  lines: 1
  ignored_header_bytes: 0

# Deploy-time: fail if any matched file is smaller than the window
find /var/log/app -name '*.log' -size -1k -print -quit | grep -q . && \
  echo 'WARN: files smaller than fingerprint window matched by glob'

Prevention

When it happens

Trigger: A globbed file smaller than the fingerprint buffer/line requirement — e.g. `fingerprint.lines = 1` on an empty file being written, or higher `lines` on a file with fewer lines; files with more `ignored_header_bytes` than actual content; a gzip member header that decompresses to fewer bytes than requested.

Common situations: Log rotation leaving zero-byte or one-line stub files matched by the glob; setting `fingerprint.lines` > 1 (as some guides suggest to survive identical first lines) on directories with short files; ignoring header bytes of files without those headers.

Related errors


AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20). Data as JSON: /api/errors/f720ec0d27706a5c. Report an issue: GitHub.