Skip to content
Latchkey

Laravel "The stream or file ... log ... could not be opened" in CI

Monolog could not open the daily or single log file under storage/logs. The directory is missing or not writable by the CI user. Create and chmod it, or switch the log channel to stderr so CI captures logs without touching disk.

What this error means

A request or command fails with "The stream or file \"storage/logs/laravel.log\" could not be opened in append mode: Failed to open stream: Permission denied" or "No such file or directory".

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

Diagnose it: version, extensions, and limits

Terminal
php -v
php -m
php -i | grep -E "memory_limit|max_execution_time|error_reporting"

# a runner default is often far tighter than your local php.ini
php -d memory_limit=-1 vendor/bin/<tool>

Common causes

storage/logs is missing or unwritable

The logs directory was not created after checkout, or its permissions do not allow the runner user to write, so Monolog fails to open the file.

The default file log channel is used in CI

Writing to a file adds a filesystem dependency that a stateless CI job often does not need and that breaks on permission issues.

How to fix it

Create and make the logs directory writable

  1. Create storage/logs if missing.
  2. chmod it writable for the runner user.
  3. Re-run so Monolog can append to the file.
Terminal
mkdir -p storage/logs
chmod -R 777 storage/logs

Log to stderr in CI

Set LOG_CHANNEL=stderr so logs go to the job output and no file needs to be writable.

.github/workflows/ci.yml
env:
  LOG_CHANNEL: stderr

How to prevent it

  • Keep storage/logs present and writable in CI.
  • Prefer LOG_CHANNEL=stderr for stateless runners.
  • Match runner user ownership to the checked-out tree.

Frequently asked questions

What causes Laravel "The stream or file ... log ... could not be opened" in CI?
There are 2 common causes: storage/logs is missing or unwritable and the default file log channel is used in ci. The logs directory was not created after checkout, or its permissions do not allow the runner user to write, so Monolog fails to open the file.
How do I fix Laravel "The stream or file ... log ... could not be opened" in CI?
There are 2 fixes depending on which cause you have: create and make the logs directory writable and log to stderr in ci. Work through them in order, since the first is the most common.
What does Laravel "The stream or file ... log ... could not be opened" in CI actually mean?
A request or command fails with "The stream or file \"storage/logs/laravel.log\" could not be opened in append mode: Failed to open stream: Permission denied" or "No such file or directory".
How do I stop Laravel "The stream or file ... log ... could not be opened" in CI happening again?
Keep storage/logs present and writable in CI. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card