应先检查缓存目录属主是否为当前用户,再确认composer_cache_dir环境变量是否覆盖配置,最后排查挂载限制或ci并发冲突。

报错说“Writing cache file … Permission denied”,先看属主不是权限位
这类错误几乎从不因为chmod数字太小,而是目录被root或其他用户占了——比如你曾用sudo composer install,或CI脚本以root身份跑过。终端报错里带的路径(如~/.composer/cache/repo/https---packagist.org/)就是目标,直接ls -ld它:
-
ls -ld $(composer config --global cache-dir)—— 看第三列是不是你当前用户名($(whoami)) - 如果不是,执行
sudo chown -R $USER:$USER $(composer config --global cache-dir) - 别用
chmod -R 777,它掩盖归属问题,还可能触发CI安全扫描失败
COMPOSER_CACHE_DIR环境变量优先级最高,config设置可能失效
composer config --global cache-dir /path/to/cache只是写进配置文件,真正起作用的是环境变量COMPOSER_CACHE_DIR。它一旦被设了,就完全绕过config值。
- 检查是否被覆盖:
echo $COMPOSER_CACHE_DIR,非空就说明config没生效 - 如果想用config方式,删掉该环境变量;如果保留环境变量,确保路径存在且属主正确:
mkdir -p /path/to/cache && sudo chown $USER:$USER /path/to/cache - 路径必须是绝对路径,
~不会被解析,/home/alex/.cache/composer才有效
CI/CD里缓存目录选错位置,会导致并发冲突或静默 fallback
在GitHub Actions、GitLab CI等共享构建机上,多个job共用同一缓存目录会出问题:A job正在写repo/,B job读到半截JSON;不同PHP版本共用dist包,autoloader生成错乱。
- 推荐按PHP版本隔离:
composer config --global cache-dir "$HOME/.composer-cache-$PHP_VERSION" - 不要设成
/tmp/composer-cache——某些系统定时清空/tmp,导致重复下载 - 确认真实路径用
composer diag | grep "Cache directory",别信composer config cache-dir输出 - 如果
composer diag显示Cache is not working due to permissions,说明路径存在但不可写,Composer已悄悄退回到默认位置
缓存路径改完仍报错?可能是挂载层或文件系统写保护
尤其在Docker、WSL2或NFS挂载场景下,ls -l显示可写,但实际无法创建文件——这是挂载参数或文件系统限制,不是Composer的问题。
- 查挂载参数:
mount | grep $(df . | tail -1 | awk '{print $1}'),重点看有没有ro(只读)、noexec(影响Phar解包) - WSL2中项目放在
/mnt/c/,默认metadata=false,chown无效,得在/etc/wsl.conf开metadata=true - 临时验证法:
export COMPOSER_CACHE_DIR="/tmp/composer-cache-$$" && composer install --no-cache,成功说明原路径被系统级锁死
最常被忽略的一点:报错路径里的“缓存目录”未必是你以为的那个——它可能是COMPOSER_CACHE_DIR指向的路径,也可能是composer diag里显示的真实路径,两者不一致时,修错地方就白忙活。











