doctrine/orm · error · LogicException

If you want to use a "READ_WRITE" cache an implementation…

Error message

If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you want to use it please provide a valid directory, DefaultCacheFactory#setFileLockRegionDirectory(). 

What it means

LogicException from DefaultCacheFactory::getRegion() (src/Cache/DefaultCacheFactory.php:160). Something is cached with usage READ_WRITE, and the default factory implements READ_WRITE locking via FileLockRegion — but no lock directory was configured, so it cannot build the required ConcurrentRegion and refuses to fall back to an unlocked region (which would silently break consistency).

Solutions

  1. Call $cacheFactory->setFileLockRegionDirectory('/var/cache/app/doctrine-lock') (a writable, preferably local, path) before the entity manager is used — regions are built lazily and memoized, so configure it in the factory bootstrap.
  2. In Symfony with doctrine-bundle, set the second-level-cache file lock region directory option (doctrine.orm.second_level_cache.file_lock_region_directory) instead of hand-calling the factory.
  3. If strict locking is unnecessary, change usage to NONSTRICT_READ_WRITE, which needs no lock directory.
  4. Keep the directory out of the project root and exclude it from deployments/rsync so lock files do not leak between releases.

Example fix

// before
$factory = new DefaultCacheFactory($regionsConfig, $cacheItemPool);
$ormConfig->setSecondLevelCacheEnabled(true);
// entity has #[Cache(usage: 'READ_WRITE')] -> LogicException at runtime

// after
$factory = new DefaultCacheFactory($regionsConfig, $cacheItemPool);
$factory->setFileLockRegionDirectory(sys_get_temp_dir() . '/doctrine-slc-lock');
$ormConfig->setSecondLevelCacheEnabled(true);
$ormConfig->getSecondLevelCacheConfiguration()->setCacheFactory($factory);
Defensive patterns

Strategy: validation

Validate before calling

$factory = new DefaultCacheFactory($regionsConfig, $pool);
if ($anyReadWriteUsage) {
    $dir = sys_get_temp_dir() . '/doctrine-slc-lock';
    if (! is_dir($dir)) { mkdir($dir, 0775, true); }
    $factory->setFileLockRegionDirectory($dir);
}

Prevention

When it happens

Trigger: Any entity or association mapped with `#[Cache(usage: 'READ_WRITE')]` (second-level cache enabled) while DefaultCacheFactory::setFileLockRegionDirectory() was never called or was called with '' — the factory's $fileLockRegionDirectory is null/empty when the region is first requested.

Common situations: Enabling the second-level cache in a new project and copying `usage: READ_WRITE` from docs without configuring the lock directory; Symfony doctrine-bundle setups missing the file_lock_region_directory setting; turning on SLI cache after an upgrade where the directory config lived in removed bootstrap code.

Related errors


AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21). Data as JSON: /api/errors/a03f87d4fb17b3d9. Report an issue: GitHub.

Appendix: source

Thrown at src/Cache/DefaultCacheFactory.php:160

    /**
     * {@inheritDoc}
     */
    public function getRegion(array $cache): Region
    {
        if (isset($this->regions[$cache['region']])) {
            return $this->regions[$cache['region']];
        }

        $name     = $cache['region'];
        $lifetime = $this->regionsConfig->getLifetime($cache['region']);
        $region   = new DefaultRegion($name, $this->cacheItemPool, $lifetime);

        if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) {
            if (
                $this->fileLockRegionDirectory === '' ||
                $this->fileLockRegionDirectory === null
            ) {
                throw new LogicException(
                    'If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, ' .
                    'The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you want to use it please provide a valid directory, DefaultCacheFactory#setFileLockRegionDirectory(). ',
                );
            }

            $directory = $this->fileLockRegionDirectory . DIRECTORY_SEPARATOR . $cache['region'];
            $region    = new FileLockRegion($region, $directory, (string) $this->regionsConfig->getLockLifetime($cache['region']));
        }

        return $this->regions[$cache['region']] = $region;
    }

    public function getTimestampRegion(): TimestampRegion
    {
        if ($this->timestampRegion === null) {
            $name     = Cache::DEFAULT_TIMESTAMP_REGION_NAME;
            $lifetime = $this->regionsConfig->getLifetime($name);

View on GitHub (pinned to d9b9ff7301)