doctrine/orm · error · InvalidArgumentException
Unable to use access strategy type of [%s] without a Concurr
Error message
Unable to use access strategy type of [%s] without a ConcurrentRegion
What it means
InvalidArgumentException from DefaultCacheFactory::buildCachedEntityPersister() (src/Cache/DefaultCacheFactory.php:82). An entity is mapped with CACHE_USAGE_READ_WRITE (the `#[Cache(usage: 'READ_WRITE')]` strategy), which needs a lockable ConcurrentRegion to keep cached state consistent across processes — but the region resolved for that entity's cache region name is a plain Region instance.
Source
Thrown at src/Cache/DefaultCacheFactory.php:82
}
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata): CachedEntityPersister
{
assert($metadata->cache !== null);
$region = $this->getRegion($metadata->cache);
$usage = $metadata->cache['usage'];
if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {
return new ReadOnlyCachedEntityPersister($persister, $region, $em, $metadata);
}
if ($usage === ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE) {
return new NonStrictReadWriteCachedEntityPersister($persister, $region, $em, $metadata);
}
if ($usage === ClassMetadata::CACHE_USAGE_READ_WRITE) {
if (! $region instanceof ConcurrentRegion) {
throw new InvalidArgumentException(sprintf('Unable to use access strategy type of [%s] without a ConcurrentRegion', $usage));
}
return new ReadWriteCachedEntityPersister($persister, $region, $em, $metadata);
}
throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));
}
public function buildCachedCollectionPersister(
EntityManagerInterface $em,
CollectionPersister $persister,
AssociationMapping $mapping,
): CachedCollectionPersister {
assert(isset($mapping->cache));
$usage = $mapping->cache['usage'];
$region = $this->getRegion($mapping->cache);
if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {View on GitHub (pinned to d9b9ff7301)
Solutions
- Register a ConcurrentRegion (e.g. FileLockRegion wrapping your region) for that region name via $cacheFactory->setRegion(new FileLockRegion($region, $dir, $lockLifetime)).
- Or set DefaultCacheFactory::setFileLockRegionDirectory($dir) so getRegion() wraps READ_WRITE regions in a FileLockRegion automatically, and make sure the region name isn't pre-registered as a plain region.
- Downgrade the entity to 'NONSTRICT_READ_WRITE' if strict locking is not required — it works with plain regions.
- Give READ_WRITE entities their own region name so a previously-built non-concurrent region cannot be reused.
Example fix
// before: READ_WRITE entity resolves to a plain DefaultRegion
$factory->setRegion(new DefaultRegion('my_entity_region', $pool, 3600));
// #[Cache(usage: 'READ_WRITE', region: 'my_entity_region')] on the entity -> InvalidArgumentException
// after: wrap it in a FileLockRegion (a ConcurrentRegion)
$factory->setRegion(
new FileLockRegion(
new DefaultRegion('my_entity_region', $pool, 3600),
'/var/lock/doctrine/my_entity_region',
60,
)
); Defensive patterns
Strategy: validation
Validate before calling
// Before enabling READ_WRITE, make sure the region is concurrent
$factory = new DefaultCacheFactory($regionsConfig, $pool);
if ($usesReadWrite) {
$factory->setRegion(new FileLockRegion(
new DefaultRegion('my_region', $pool, 3600),
$lockDir . '/my_region',
60,
));
} Prevention
- Call setFileLockRegionDirectory() in the cache-factory bootstrap, before any entity manager is created.
- Give each cache usage strategy its own region name to avoid a plain region being reused for READ_WRITE.
- Only inject custom regions that are ConcurrentRegion instances when any mapped entity uses READ_WRITE.
When it happens
Trigger: A custom region registered via DefaultCacheFactory::setRegion(new DefaultRegion(...)) under the same region name the entity uses; or the region for that name was already created (and memoized in $this->regions) as a non-concurrent DefaultRegion because another entity with the same region name used READ_ONLY/NONSTRICT_READ_WRITE first. Note: if no directory was configured at all you get the separate LogicException about setFileLockRegionDirectory() first — this exception means a region exists but has the wrong type.
Common situations: Several entities sharing one region name while mixing cache usage strategies; swapping in a custom region implementation (e.g. Redis-backed DefaultRegion) and forgetting READ_WRITE entities need a ConcurrentRegion decorator; upgrading second-level cache config where regions were previously per-usage.
Related errors
- If you want to use a "READ_WRITE" cache an implementation of
- Unrecognized access strategy type [%s]
- The directory "%s" does not exist and could not be created.
- The directory "%s" is not writable.
- Invalid cache usage "%s"
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/91bca6fc82435c16.
Report an issue: GitHub.