rectorphp/rector · error · CachingException

Could not write data to cache file %s.

Error message

Could not write data to cache file %s.

What it means

FileCacheStorage::save() writes each item to a temp file then @copy()s it into the two-level cache directory. If the copy fails and the platform is not Windows-with-existing-target, it throws CachingException naming the unreachable cache file. This is a filesystem-level failure: permissions, missing directory, or a full disk, almost never a Rector bug.

Source

Thrown at src/Caching/ValueObject/Storage/FileCacheStorage.php:77

        $this->filesystem->mkdir($cacheFilePaths->getFirstDirectory());
        $this->filesystem->mkdir($cacheFilePaths->getSecondDirectory());
        $filePath = $cacheFilePaths->getFilePath();
        $tmpPath = \sprintf('%s/%s.tmp', $this->directory, Random::generate());
        $errorBefore = \error_get_last();
        $exported = @\var_export(new CacheItem($variableKey, $data), \true);
        $errorAfter = \error_get_last();
        if ($errorAfter !== null && $errorBefore !== $errorAfter) {
            throw new CachingException(\sprintf('Error occurred while saving item %s (%s) to cache: %s', $key, $variableKey, $errorAfter['message']));
        }
        // for performance reasons we don't use SmartFileSystem
        FileSystem::write($tmpPath, \sprintf("<?php declare(strict_types = 1);\n\nreturn %s;", $exported), null);
        $copySuccess = @\copy($tmpPath, $filePath);
        @\unlink($tmpPath);
        if ($copySuccess) {
            return;
        }
        if (\DIRECTORY_SEPARATOR === '/' || !\file_exists($filePath)) {
            throw new CachingException(\sprintf('Could not write data to cache file %s.', $filePath));
        }
    }
    public function clean(string $key): void
    {
        $cacheFilePaths = $this->getCacheFilePaths($key);
        $this->processRemoveCacheFilePath($cacheFilePaths);
        $this->processRemoveEmptyDirectory($cacheFilePaths->getSecondDirectory());
        $this->processRemoveEmptyDirectory($cacheFilePaths->getFirstDirectory());
    }
    public function clear(): void
    {
        FileSystem::delete($this->directory);
    }
    private function processRemoveCacheFilePath(CacheFilePaths $cacheFilePaths): void
    {
        $filePath = $cacheFilePaths->getFilePath();
        if (!$this->filesystem->exists($filePath)) {
            return;

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Fix ownership/permissions of the cache directory: rm -rf .cache/rector (or /tmp/rector) so the current user recreates it
  2. Point the cache to a writable, per-user location: ->withCacheDirectory(__DIR__ . '/.rector-cache') or the cacheDirectory option
  3. Check disk space and quota: df -h on the filesystem holding the cache dir
  4. In CI, avoid concurrent rector runs sharing one cache directory (matrix jobs without distinct caches)

Example fix

# before: cache dir owned by root, run as ci user
vendor/bin/rector process src  # CachingException: Could not write data to cache file

# after: give the run its own writable cache
rm -rf .cache/rector
vendor/bin/rector process src --cache-directory .rector-cache-ci
Defensive patterns

Strategy: fallback

Validate before calling

// preflight in CI: verify the cache directory is writable by this user
$cacheDir = sys_get_temp_dir() . '/rector'; // or your configured cacheDirectory
if (is_dir($cacheDir) && ! is_writable($cacheDir)) {
    fwrite(STDERR, "Cache dir not writable: {$cacheDir}\n");
    exit(1);
}

Try / catch

catch \Rector\Caching\Exception\CachingException, inspect the path in the message, fix permissions/chown, then retry the run; do not ignore -- a failed cache write silently costs full re-analysis on every run.

Prevention

When it happens

Trigger: The cache directory (default under sys temp or the configured cacheDirectory) is not writable by the current user: cache created by root then reused by a CI user, a read-only mount, disk quota exhausted, or a parallel job racing to delete directories (clean/clear-cache) while others save.

Common situations: Docker/CI where one stage runs rector as root and another as non-root; deploy pipelines running rector on read-only artifacts; /tmp cleanup daemons removing the temp file between write and copy.

Related errors


AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21). Data as JSON: /api/errors/08ee92ebca0e3b7a. Report an issue: GitHub.