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:
[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:
[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:warmupas the same user that serves the application - Use ACL (
setfacl) for directories shared between multiple users - Set
umask 0002in deployment scripts for group-writable files - Add a post-deploy health check that verifies the web server can read cache files
- Use
APP_ENV=prodconsistently 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