vercel/turborepo · warning
error opening log file: {err:?}
Error message
error opening log file: {err:?} What it means
replay_logs (crates/turborepo-ui/src/logs.rs:99) opens a previously written task log file to replay its output (typically after a cache hit or in watch mode). If File::open fails, turbo emits this warning and returns Error::CannotReadLogs(err); the stored log cannot be shown.
Source
Thrown at crates/turborepo-ui/src/logs.rs:100
if let Some(log_file) = &mut self.log_file {
log_file.flush()?;
}
if let Some(prefixed_writer) = &mut self.writer {
prefixed_writer.flush()?;
}
Ok(())
}
}
pub fn replay_logs<W: Write>(
mut output: W,
log_file_name: &AbsoluteSystemPath,
) -> Result<(), Error> {
debug!("start replaying logs");
let log_file = File::open(log_file_name).map_err(|err| {
turborepo_log::warn(
turborepo_log::Source::turbo(turborepo_log::Subsystem::Logs),
format!("error opening log file: {err:?}"),
)
.emit();
Error::CannotReadLogs(err)
})?;
let mut log_reader = BufReader::new(log_file);
let mut buffer = Vec::new();
loop {
let num_bytes = log_reader
.read_until(b'\n', &mut buffer)
.map_err(Error::CannotReadLogs)?;
if num_bytes == 0 {
break;
}
View on GitHub (pinned to f9245100cf)
Solutions
- If logs were pruned intentionally, clean the matching cache entry too so hits and logs stay consistent (remove the whole cache entry folder or run turbo clean).
- Check the file exists and is readable: ls -l on the reported path; fix ownership/permissions of the cache dir.
- Avoid sharing one cache directory between multiple concurrent machines/users; use per-user cache dirs or a remote cache.
- If it recurs, capture the {err:?} detail — ENOENT points to pruning races, EACCES to permissions.
Example fix
# before: cache hit references a pruned log file -> error opening log file: Os { code: 2 }
turbo run build --force=false
# after: evict the half-pruned entry so it is treated as a miss
turbo clean # or: rm -rf .turbo/cache/<hash-of-the-task>
turbo run build Defensive patterns
Strategy: fallback
Validate before calling
#!/usr/bin/env bash
# before replaying logs from a cache hit, confirm the log file exists
LOG="$1"
[ -r "$LOG" ] || { echo "log missing — treating as cache miss" >&2; exit 3; }
cat "$LOG" Try / catch
// replay_logs returns Result<(), turborepo_ui::Error>
match replay_logs(&mut out, &log_path) {
Ok(()) => {}
Err(e) => {
// degrade gracefully: show a placeholder instead of failing the task view
eprintln!("(cached logs unavailable: {e:?})");
}
} Prevention
- Evict cache entries atomically — delete the whole entry folder including logs, never partial contents.
- Give each user/runner its own cache directory to avoid cross-permission reads.
- Back important runs with --output-logs=full or remote artifacts if logs must survive.
When it happens
Trigger: Calling replay_logs with a path that does not exist (ENOENT — the log was deleted or never written), is not readable (EACCES), is a directory, or is locked by another process on Windows.
Common situations: A cache entry survives but its companion log file was pruned (turbo clean / cache eviction / manual deletion of files inside the cache dir), cache directory copied between machines with lost permissions, or concurrent runs racing over the same cache directory.
Related errors
- refusing to write structured log to symlink: {}
- error creating log file directory: {err:?}
- error creating log file: {err:?}
- no caches are enabled
- Found both turbo.json and turbo.jsonc in the same directory:
AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17).
Data as JSON: /api/errors/2eb24b8db9f56f35.
Report an issue: GitHub.