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
- 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.
- 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.
- If strict locking is unnecessary, change usage to NONSTRICT_READ_WRITE, which needs no lock directory.
- 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
- Treat setFileLockRegionDirectory() as mandatory config whenever READ_WRITE appears in mappings.
- Default to NONSTRICT_READ_WRITE in shared examples/docs unless locking is configured.
- Assert during bootstrap: if any metadata uses READ_WRITE, the lock directory must be set and writable.
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
- Invalid cache usage
- Unable to use access strategy type of
- Invalid argument "--entity-class"
- Lazy loading proxies require PHP 8.4 or higher.
- Missing arguments "--owner-class" "--association"
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)