{"record":{"id":"91bca6fc82435c16","repo":"doctrine/orm","slug":"unable-to-use-access-strategy-type-of-s-without","errorCode":null,"errorMessage":"Unable to use access strategy type of [%s] without a ConcurrentRegion","messagePattern":"Unable to use access strategy type of \\[(.+?)\\] without a ConcurrentRegion","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Cache/DefaultCacheFactory.php","lineNumber":82,"sourceCode":"    }\n\n    public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata): CachedEntityPersister\n    {\n        assert($metadata->cache !== null);\n        $region = $this->getRegion($metadata->cache);\n        $usage  = $metadata->cache['usage'];\n\n        if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {\n            return new ReadOnlyCachedEntityPersister($persister, $region, $em, $metadata);\n        }\n\n        if ($usage === ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE) {\n            return new NonStrictReadWriteCachedEntityPersister($persister, $region, $em, $metadata);\n        }\n\n        if ($usage === ClassMetadata::CACHE_USAGE_READ_WRITE) {\n            if (! $region instanceof ConcurrentRegion) {\n                throw new InvalidArgumentException(sprintf('Unable to use access strategy type of [%s] without a ConcurrentRegion', $usage));\n            }\n\n            return new ReadWriteCachedEntityPersister($persister, $region, $em, $metadata);\n        }\n\n        throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));\n    }\n\n    public function buildCachedCollectionPersister(\n        EntityManagerInterface $em,\n        CollectionPersister $persister,\n        AssociationMapping $mapping,\n    ): CachedCollectionPersister {\n        assert(isset($mapping->cache));\n        $usage  = $mapping->cache['usage'];\n        $region = $this->getRegion($mapping->cache);\n\n        if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/doctrine/orm/blob/d9b9ff73016bf598ae07515f97289ce8074e97a5/src/Cache/DefaultCacheFactory.php#L64-L100","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: READ_WRITE entity resolves to a plain DefaultRegion\n$factory->setRegion(new DefaultRegion('my_entity_region', $pool, 3600));\n// #[Cache(usage: 'READ_WRITE', region: 'my_entity_region')] on the entity -> InvalidArgumentException\n\n// after: wrap it in a FileLockRegion (a ConcurrentRegion)\n$factory->setRegion(\n    new FileLockRegion(\n        new DefaultRegion('my_entity_region', $pool, 3600),\n        '/var/lock/doctrine/my_entity_region',\n        60,\n    )\n);","handlingStrategy":"validation","validationCode":"// Before enabling READ_WRITE, make sure the region is concurrent\n$factory = new DefaultCacheFactory($regionsConfig, $pool);\nif ($usesReadWrite) {\n    $factory->setRegion(new FileLockRegion(\n        new DefaultRegion('my_region', $pool, 3600),\n        $lockDir . '/my_region',\n        60,\n    ));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["doctrine-orm","second-level-cache","read-write-cache","cache-region"],"backgroundTag":"cache-region-type-mismatch","analyzedSha":"d9b9ff73016bf598ae07515f97289ce8074e97a5","analyzedAt":"2026-08-21T06:13:15.863Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}