Introduction

Symfony cache warmup fails with permission errors when the deployment user (e.g., the CI/CD runner or deployment script user) does not have write access to the var/cache/ directory, or when the web server user (www-data, nginx, apache) cannot read the cached files written by the deployment process. This error blocks application deployment and causes 500 errors when the web server cannot read pre-warmed cache files. The problem is exacerbated in deployment pipelines where one user runs cache:warmup and a different user serves the application.

Symptoms

``` In Filesystem.php line 123: Failed to remove directory "/var/www/myapp/var/cache/prod": unlink(/var/www/myapp/var/cache/prod/annotations.php): Permission denied

cache:warmup [--no-optional-warmers] ```

Or:

bash
[Symfony\Component\Filesystem\Exception\IOException]
  Failed to write cache file "/var/www/myapp/var/cache/prod/pools/system/metadata/Metadata.php".

Web server error after deployment:

bash
[crit] 12345#0: *67 open() "/var/www/myapp/var/cache/prod/ContainerXYZ/MyApp_KernelProdContainer.php"
failed (13: Permission denied)

Common Causes

  • Different users for deployment and web serving: Deployer user writes cache, www-data cannot read it
  • Stale cache from previous deployment: Old cache files owned by a different user block new writes
  • Umask too restrictive: Deployment script creates files with 0700 permissions
  • Docker volume mount permissions: Container user differs from host user UID/GID
  • SELinux context mismatch: Security context prevents web server from reading deployment files
  • Shared hosting environment: Multiple users sharing the same cache directory

Step-by-Step Fix

Step 1: Set correct permissions on cache directory

```bash # Set ownership to web server user sudo chown -R www-data:www-data /var/www/myapp/var/cache

# Set permissions - directories 755, files 644 find /var/www/myapp/var/cache -type d -exec chmod 755 {} \; find /var/www/myapp/var/cache -type f -exec chmod 644 {} \; ```

Step 2: Use ACL for shared access (both deployer and www-data)

```bash # Install ACL if not present sudo apt-get install acl

# Set ACL on the cache directory sudo setfacl -R -m u:www-data:rwx -m u:deployer:rwx /var/www/myapp/var/cache sudo setfacl -dR -m u:www-data:rwx -m u:deployer:rwx /var/www/myapp/var/cache ```

The -d flag sets default ACL so new files inherit the permissions.

Step 3: Configure umask in deployment script

```bash #!/bin/bash # deploy.sh umask 0002 # Files: 664, Directories: 775 (group-writable)

# Clear cache rm -rf var/cache/prod

# Warm up cache php bin/console cache:warmup --env=prod --no-debug

# Set ownership after warmup sudo chown -R www-data:www-data var/cache/prod ```

Step 4: Use a shared cache directory in Docker

```dockerfile FROM php:8.1-fpm

# Create a user with the same UID as the host user ARG UID=1000 ARG GID=1000 RUN groupadd -g $GID appuser && \ useradd -u $UID -g $GID -m appuser

# Set cache directory with correct permissions RUN mkdir -p /var/www/myapp/var/cache && \ chown -R appuser:appuser /var/www/myapp/var && \ chmod -R 775 /var/www/myapp/var

USER appuser WORKDIR /var/www/myapp ```

Prevention

  • Always run cache:warmup as the same user that serves the application
  • Use ACL (setfacl) for directories shared between multiple users
  • Set umask 0002 in deployment scripts for group-writable files
  • Add a post-deploy health check that verifies the web server can read cache files
  • Use APP_ENV=prod consistently across warmup and runtime
  • Clear the cache directory (rm -rf var/cache/prod) before warming to avoid stale file conflicts
  • Document the deployment user and web server user in your deployment runbook