Linux / Bash

How to Fix "chmod: cannot access: No such file or directory" in Bash Script

4 min read by DebuggedIt

Quick answer

Your script calls chmod on a file that should exist, but it fails claiming the file isn't there. This is a path resolution problem β€” the file exists somewhere,...

Your script calls chmod on a file that should exist, but it fails claiming the file isn't there. This is a path resolution problem β€” the file exists somewhere, just not at the exact location chmod looked, usually because of a wrong working directory or an unexpanded variable.

The Problem

Running a script or deployment step fails partway through with this exact error:

$ ./deploy.sh
chmod: cannot access 'build/output/app': No such file or directory

Sometimes it's tied to a variable that didn't expand the way you expected:

$ chmod +x $BUILD_DIR/app
chmod: cannot access '/app': No such file or directory

Notice the path is missing the intended directory entirely β€” $BUILD_DIR resolved to an empty string, leaving just /app.

Why It Happens

This error means chmod did exactly what it was told β€” look for a file at a specific path β€” and that path simply doesn't exist at the moment the command ran. The most common causes:

  • The script runs from a different working directory than you expect, so a relative path like build/output/app resolves against the wrong base directory.
  • An earlier build or copy step failed silently, so the file was never actually created in the first place, and chmod is just the first command to notice.
  • An unset or empty environment variable in the path, like $BUILD_DIR above, silently collapses to nothing instead of erroring, producing a malformed path.
  • A typo in the filename or directory structure that doesn't match what a prior step actually generated.
  • The script assumes a file exists synchronously right after an asynchronous or backgrounded step that hasn't finished writing it yet.

The Fix

Start by confirming your actual working directory when the script runs, since relative paths are resolved against it:

pwd
ls -la build/output/

If the file genuinely isn't there, check the step before chmod that's supposed to create it, and look for a silently failed command earlier in the script. Add set -e at the top of your script so it stops immediately on the first failing command instead of continuing on and hitting a confusing, unrelated error later:

#!/bin/bash
set -e

make build
chmod +x build/output/app

For variable-related path issues, enable set -u as well, which makes the script fail loudly on any unset variable instead of silently substituting an empty string:

#!/bin/bash
set -euo pipefail

chmod +x "$BUILD_DIR/app"

With set -u active, an unset $BUILD_DIR now fails immediately with a clear message instead of silently producing a broken path:

./deploy.sh: line 5: BUILD_DIR: unbound variable

Always quote path variables to avoid word-splitting issues if a path contains spaces, and print the resolved path right before using it while debugging:

echo "Attempting chmod on: $BUILD_DIR/app"
chmod +x "$BUILD_DIR/app"

Still Not Working?

If the file's existence is timing-dependent β€” for example, it's written by a background process or a step running in a CI pipeline with async file syncing β€” add a short, explicit wait-and-check loop instead of assuming it's immediately available the instant the previous command returns:

for i in {1..10}; do
    [ -f build/output/app ] && break
    sleep 1
done

if [ ! -f build/output/app ]; then
    echo "build/output/app was never created" >&2
    exit 1
fi

chmod +x build/output/app

This gives the file up to 10 seconds to appear, failing with a clear message if it genuinely never shows up, which is far easier to diagnose than a raw chmod error buried in a longer script's output.

It's also worth building a habit of validating assumptions explicitly at the start of any script that touches file permissions, rather than discovering a missing file only when chmod fails partway through a longer deployment sequence. A short preflight check at the top of the script can catch a whole class of these errors before any real work begins:

#!/bin/bash
set -euo pipefail

REQUIRED_FILES=("build/output/app" "config/settings.yaml")
for f in "${REQUIRED_FILES[@]}"; do
    if [ ! -e "$f" ]; then
        echo "Missing required file: $f" >&2
        exit 1
    fi
done

chmod +x build/output/app

This pattern fails fast with a clear, specific message pointing at exactly which file is missing, instead of letting the script get partway through and fail on an unrelated-looking chmod error that doesn't immediately reveal the actual root cause to whoever's debugging it later.