Skip to content
Latchkey

Laravel storage/bootstrap-cache permission denied in CI

Laravel writes compiled views, cache, and logs under storage/ and bootstrap/cache/. If those directories are missing or not writable by the runner user, bootstrapping throws a permission or "valid cache path" error before any code runs.

What this error means

The app fails to boot with "Please provide a valid cache path." or "failed to open stream: Permission denied" for a path under storage/framework or bootstrap/cache.

php artisan
  UnexpectedValueException

  The stream or file "storage/logs/laravel.log" could not be opened
  in append mode: Failed to open stream: Permission denied

Common causes

storage subdirectories are missing

A fresh checkout may not include empty storage/framework/{cache,sessions,views} dirs, so Laravel cannot write compiled output.

Directories are not writable by the CI user

A checked-out tree or container volume owned by another user leaves storage and bootstrap/cache non-writable.

How to fix it

Create and chmod the writable directories

  1. Ensure the framework subdirectories exist.
  2. Make storage and bootstrap/cache writable in a setup step.
  3. Then boot artisan and run tests.
.github/workflows/ci.yml
- run: |
    mkdir -p storage/framework/{cache,sessions,views} bootstrap/cache
    chmod -R 777 storage bootstrap/cache

Fix ownership in a containerized runner

When the tree is owned by root but the process runs as another user, chown the writable paths to the runner user.

Terminal
chown -R "$(id -u):$(id -g)" storage bootstrap/cache

How to prevent it

  • Keep .gitkeep files so storage subdirectories exist after checkout.
  • chmod storage and bootstrap/cache writable as a setup step.
  • Match container user ownership to the runner user.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →