"No such file or directory" When the File Exists
What This Article Solves
- Why
lsshows a file yet you still getNo such file or directory - How to tell hidden characters, CRLF, broken symlinks, and a missing dynamic linker apart
- How to pinpoint an "exists but unreachable" file with concrete commands and fix it
Quick Answer (fastest triage)
When something "is there but isn't," it is usually one of these four:
- Hidden characters in the filename -> reveal with
ls -b - A script shebang with CRLF or a wrong path -> check line ends with
cat -A - A symlink whose target is gone -> red in
ls -la, confirm withreadlink -f - An executable missing its dynamic linker (ELF interpreter) -> check type with
file
Running just ls -b (hidden chars) and ls -la (broken links) isolates 80% of cases.
Assumptions (target environment)
- OS: Ubuntu / Debian family (the reasoning applies to other distros too)
- Shell: bash
- Examples use placeholder names like
targetand./run
Why Does an Existing File Report "No such file or directory"?
Conclusion: Usually the filename you see and the path string the kernel looks up do not match byte for byte, or the file's backing entity (link target, interpreter) is missing.
ls output is formatted for humans: trailing spaces, control characters, and broken-link states are not obvious at a glance. System calls like open() and stat(), however, compare the path string byte for byte. So two names can look identical on screen yet differ in their actual bytes, and the kernel returns ENOENT (No such file or directory).
This error splits into two families:
- Path-string mismatch: hidden characters in the name, a shifted relative path, CRLF contamination
- Missing backing entity: a deleted symlink target, a missing dynamic linker for a binary
We triage them below in order of frequency.
Cause 1: Hidden Characters in the Filename
Conclusion: Use
ls -bto print escaped filenames and expose trailing spaces, tabs, or full-width spaces.
Copy-paste and generated scripts can append a trailing space, newline, or full-width space to a filename. It looks like target, but if the real name is target (trailing space), then cat target naturally fails with No such file or directory.
ls -b
target\
A trailing \ (backslash + space) proves the name contains whitespace. Tabs show as \t; a full-width space shows as octal like \343\200\200.
To target the file reliably, use Tab completion or pick up the real bytes with find and rename it.
find . -maxdepth 1 -name 'target*' -print mv -i 'target ' target
ls | cat -A helps too. cat -A marks each line end with $, so a stray trailing space appears just before the $.
Cause 2: The Script Shebang Has CRLF or a Wrong Path
Conclusion: If
./script.sh: No such file or directoryappears while the file clearly exists, suspect a CRLF line ending or a non-existent interpreter path in the shebang.
You run ./deploy.sh, get No such file or directory, yet ls -l deploy.sh shows it right there. This is the classic shebang problem. Files edited on Windows use CRLF (\r\n) line endings, so #!/bin/bash is read as #!/bin/bash\r. The kernel then looks for an interpreter at the path /bin/bash\r and fails.
cat -A deploy.sh | head -1
#!/bin/bash^M$
A ^M (CR) at the line end confirms CRLF. Strip it with sed or dos2unix.
sed -i 's/\r$//' deploy.sh
The shebang path itself can also be wrong (for example #!/usr/local/bin/python while the real binary is /usr/bin/python3). Check the path with head -1 and confirm it exists with command -v.
head -1 deploy.sh command -v python3
For the full procedure see Fix bad interpreter error.
Cause 3: A Symlink Whose Target Is Gone
Conclusion: The link itself still shows in
ls, but a dangling symlink returnsNo such file or directoryon access. Confirm with the color inls -laandreadlink -f.
A symbolic link is a reference to another path. When the target is deleted or moved, the link file stays while its contents vanish. The name appears in ls, yet you cannot open it.
ls -la target
lrwxrwxrwx 1 user user 18 Jun 6 10:00 target -> /opt/app/current/bin
On color terminals a broken link blinks red or shows inverted. Verify the target exists with readlink -f (which resolves to the final real path) and an ls of that result.
readlink -f target ls -la "$(readlink -f target)"
If that ls returns No such file or directory, the link is broken. Recreate it or restore the correct target.
ln -sfn /opt/app/releases/2026-06-06/bin target
Writing through a link, as in cp file target, can yield cannot create ... No such file or directory when the link's target directory is gone. Always check whether the error points at the link target.
Cause 4: The Binary Is Missing Its Dynamic Linker (ELF Interpreter)
Conclusion: When a compiled binary reports
./run: No such file or directory, the missing item is not the file but the dynamic linker (ld-linux) or ABI it requires. Check the format withfile.
An ELF executable needs a "dynamic linker" loader at startup. If the binary's architecture (32/64-bit, arm/x86) differs from the host, or the required dynamic linker is absent, the kernel rejects the loader as No such file or directory. The confusing part: what is missing is the loader, not the binary itself.
file ./run
./run: ELF 32-bit LSB executable, Intel 80386, dynamically linked, interpreter /lib/ld-linux.so.2, ...
If the loader named by interpreter /lib/ld-linux.so.2 is absent on the host, the binary cannot start. Confirm the loader exists.
ls -l /lib/ld-linux.so.2
To run a 32-bit binary on a 64-bit host, install the 32-bit runtime.
sudo dpkg --add-architecture i386 sudo apt update && sudo apt install libc6:i386
If it is an architecture mismatch (an arm binary on x86, say), it simply cannot run. Compare the file output against the host's uname -m.
Cause 5: A Missing or Shifted Path Component
Conclusion: It is not always the final file. A missing or unreadable intermediate directory also produces
No such file or directory. Trace the path one level at a time withnamei -l.
When you cannot open /opt/app/data/config.yml, the missing piece is not necessarily config.yml. The intermediate data directory may not exist or may be a broken link. namei -l resolves the path from the root down and shows exactly where it failed.
namei -l /opt/app/data/config.yml
f: /opt/app/data/config.yml drwxr-xr-x root root / drwxr-xr-x root root opt drwxr-xr-x root root app ENOENT - - data
The level where ENOENT appears (here, data) is the culprit.
A shifted relative path is common too. If cd landed somewhere unexpected, the same ./config.yml points elsewhere. Check your location with pwd, and use an absolute path when in doubt.
pwd cat /opt/app/data/config.yml
A tilde inside quotes does not expand. cat "~/notes.txt" looks for ~/notes.txt in the current directory and fails. Use cat ~/notes.txt (unquoted) or cat "$HOME/notes.txt".