ErrLookupBackground articles › "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk

"failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk

"Failed to read file", "could not read <path>", ENOENT, EACCES and "Unable to read" errors all come from one place: a program tried to open and read a file and the OS said no. This article explains the file-read failure family across open-source tools — the read happens, then what — and how to tell a missing file from a permission problem, a race, or a corrupt/unreadable one.

Distilled from 106 documented records across 49 repositories.

Background

Every error in this family starts at the same boundary: a call to a file-read primitive — fs.readFile in Node, std::fs::read_to_string in Rust, File.read or File.open in Ruby, file_get_contents in PHP, io.Copy or io.ReadAll in Go — and the OS or the decoder returning a failure. The message you see is almost never the OS error verbatim; it is a wrapper each library adds so the failure is identifiable in context: puppetlabs/puppet names the filetype class and path ('%{klass} could not read %{path}'), HumanSignal/label-studio embeds str(e) after 'Failed to read file {path}', yamadashy/repomix appends the underlying error.message, tailscale's TKA storage wraps every read phase with '%w' so the errno is preserved inside. The first debugging step is almost always to find and read the wrapped inner message, because the fix for EACCES (chmod/chown) differs completely from the fix for ENOENT (restore the file) or EISDIR (you passed a directory where a file was expected).

Despite the shared primitive, the family splits into distinct behavioral groups. One group fails hard: facebook/flow's 'check-contents input should be readable' and content_of_file_input_unsafe, and zed's 'Failed to read path' all use expect/unwrap/panic, turning an ordinary missing or non-UTF-8 file into a process crash — flow even ships a Result-returning twin (content_of_file_input) whose use avoids the panic entirely. Another group degrades gracefully: eyaltoledano/claude-task-master catches read failures in its ContextGatherer and downgrades them to console.warn while continuing, and repomix's readRawFile returns { content: null, skippedReason: 'encoding-error' } so the pipeline skips the file. Whether a read failure is fatal is a design choice by the library, not a property of the error itself.

A third pattern is the race: the file existed at scan, glob, or existsSync time but was gone (or changed) by the time the read executed. Repomix's trust prompt reads a config file that was just lstat'd; sst reads a pyproject.toml that os.Stat saw moments earlier; beekeeper-studio reads enums.json right after existsSync passed; tailscale's compaction re-reads AUM records that AllAUMs listed moments before and can vanish to a concurrent commit or purge. These TOCTOU races produce the same wrapper messages as plain missing-file errors, so a transient failure deserves one retry before deep debugging.

Finally, some members of this family are not about missing or unreadable files at all but about unreadable content: flow's read_to_string panics on non-UTF-8 bytes, siyuan distinguishes plain I/O errors from 'source changed' sentinels, and vitess's 'can't read init-db-sql-file' fires only when the open succeeded but the mid-stream read failed (EIO, or a special device that errors on read). Note that messages can also mislead: getgrav/grav's 'Bad Data' from DataFile::load sounds like corrupt content but actually means file_get_contents returned false — a failed read — while tailscale's PurgeAUMs 'reading %d (%x)' deliberately does not tolerate os.ErrNotExist, whereas its retainStateCandidate path does. Treat each library's wrapper semantics as its own contract and check the record page for specifics.

Common causes

What usually fixes it

Go deeper

Documented occurrences

…and 86 more across the corpus — use search.

Honest provenance: generated on 2026-09-02 from AI-assisted analysis of the linked records. See how records are made.