vectordotdev/vector · error
not a valid path
Error message
not a valid path
What it means
When the file server emits a read line it stores the watched file's path as a String via `Path::to_str()`, which returns None when the OS path bytes are not valid UTF-8. Vector unwraps this with expect("not a valid path"), so a single non-UTF-8 filename inside a watched directory panics the file source mid-read. The panic happens while lines are being read from that file, not at watch time.
Source
Thrown at lib/file-source/src/file_server.rs:317
&buf.clone(),
self.max_line_bytes,
buf.len(),
)
});
let sz = line.bytes.len();
trace!(
message = "Read bytes.",
path = ?watcher.path,
bytes = ?sz
);
stats.record_bytes(sz);
bytes_read += sz;
lines.push(Line {
text: line.bytes,
filename: watcher.path.to_str().expect("not a valid path").to_owned(),
file_id,
start_offset: line.offset,
end_offset: watcher.get_file_position(),
});
if bytes_read > self.max_read_bytes {
maxed_out_reading_single_file = true;
break;
}
}
stats.record("reading", start.elapsed());
if bytes_read > 0 {
global_bytes_read = global_bytes_read.saturating_add(bytes_read);
} else {
// Should the file be removed
if let Some(grace_period) = self.remove_after
&& watcher.last_read_success().elapsed() >= grace_periodView on GitHub (pinned to 3708c39b12)
Solutions
- Locate and rename/remove the offending file: walk the watched tree and flag every path where `p.to_str().is_none()` (or use `find /var/log -name '*[![:print:]]*'`)
- Tighten `include` / add `exclude_patterns` so the non-UTF-8 file falls outside the watched set
- Fix the writer that produces the non-UTF-8 name so it stops recreating it
Example fix
# before: file named app$(printf '\xff').log inside /var/log/app sudo mv /var/log/app/app$'\xff'.log /tmp/quarantine/ # or exclude it: [sources.in] exclude_patterns = ["*[[:nonascii:]]*"] # or a wildcard that skips the directory
Defensive patterns
Strategy: validation
Validate before calling
fn find_non_utf8_paths(roots: &[std::path::PathBuf]) -> Vec<std::path::PathBuf> {
walkdir::WalkDir::new(roots)
.into_iter()
.filter_map(Result::ok)
.filter(|e| e.path().to_str().is_none())
.map(|e| e.path().to_path_buf())
.collect()
}
// run before/at source start; rename or exclude anything it returns Type guard
fn is_valid_utf8_path(path: &std::path::Path) -> bool {
path.to_str().is_some()
} Prevention
- Audit watched log directories for non-UTF-8 names after onboarding new log producers
- Fix writers that emit raw-byte filenames (locale, encoding settings) instead of repeatedly renaming outputs
- Scope include globs tightly so foreign directories cannot enter the watch set
When it happens
Trigger: A file whose name contains invalid UTF-8 bytes (for example b"app\xff.log" written by a misconfigured uploader) matches an `include` glob of a `file` source; once the reader opens it and reads a line, watcher.path.to_str() returns None and the source panics.
Common situations: Log directories fed by third-party tools that write Latin-1/Windows-1252 or raw-byte filenames; files copied from systems with different encodings; containers with misconfigured locales producing byte names; files created by buggy log rotators or crash handlers.
Related errors
- failed to read glob pattern
- path and query should never fail to parse
- Serializer does not support JSON
- Paths must always start with a leading forward slash (`/`).
- Only leaf nodes should be allowed to be non-object values.
AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20).
Data as JSON: /api/errors/9ee283e864b69211.
Report an issue: GitHub.