{"record":{"id":"6f620e913da228e9","repo":"doctrine/orm","slug":"this-mapping-is-not-indexed-use-s-isindexed-t","errorCode":null,"errorMessage":"This mapping is not indexed. Use %s::isIndexed() to check that before calling %s.","messagePattern":"This mapping is not indexed\\. Use (.+?)::isIndexed\\(\\) to check that before calling (.+?)\\.","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"src/Mapping/ToManyAssociationMappingImplementation.php","lineNumber":44,"sourceCode":"     */\n    public array $orderBy = [];\n\n    /** @return array<string, 'asc'|'desc'> */\n    final public function orderBy(): array\n    {\n        return $this->orderBy;\n    }\n\n    /** @phpstan-assert-if-true !null $this->indexBy */\n    final public function isIndexed(): bool\n    {\n        return $this->indexBy !== null;\n    }\n\n    final public function indexBy(): string\n    {\n        if (! $this->isIndexed()) {\n            throw new LogicException(sprintf(\n                'This mapping is not indexed. Use %s::isIndexed() to check that before calling %s.',\n                self::class,\n                __METHOD__,\n            ));\n        }\n\n        return $this->indexBy;\n    }\n\n    /** @return list<string> */\n    public function __sleep(): array\n    {\n        $serialized = parent::__sleep();\n\n        if ($this->indexBy !== null) {\n            $serialized[] = 'indexBy';\n        }\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/doctrine/orm/blob/d9b9ff73016bf598ae07515f97289ce8074e97a5/src/Mapping/ToManyAssociationMappingImplementation.php#L26-L62","documentation":"To-many association mappings expose indexBy() to read the field that keys an indexed collection (the `indexBy` option of #[OneToMany]/#[ManyToMany]). The property is null unless the mapping declared it; isIndexed() exists exactly to guard access (it carries an @phpstan-assert-if-true). Calling indexBy() on a mapping without the option throws this LogicException.","triggerScenarios":"Calling $mapping->indexBy() directly without checking isIndexed(); indirectly via PersistentCollection::get()/offsetGet()/containsKey() on an EXTRA_LAZY collection whose mapping has no indexBy (the persisters call indexBy() to build the WHERE clause).","commonSituations":"Code assuming collections are keyed by a field ('id', 'slug') without declaring indexBy in the mapping; enabling fetch: EXTRA_LAZY and then doing $collection[$key] or isset($collection[$key]).","solutions":["Add indexBy to the association mapping: #[ManyToMany(targetEntity: Tag::class, indexBy: 'slug')] or indexBy on #[OneToMany]","Check $mapping->isIndexed() before calling indexBy()","If indexing is not intended, iterate the collection instead of key access"],"exampleFix":"// before\n#[ManyToMany(targetEntity: Tag::class)]\nprivate Collection $tags;\n$tag = $article->getTags()->get('php'); // throws\n\n// after\n#[ManyToMany(targetEntity: Tag::class, indexBy: 'slug')]\nprivate Collection $tags;\n$tag = $article->getTags()->get('php');","handlingStrategy":"validation","validationCode":"$mapping = $em->getClassMetadata($owner::class)->getAssociationMapping($field);\nif ($mapping->isIndexed()) { $key = $mapping->indexBy(); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare indexBy whenever code will key the collection","Check isIndexed() before indexBy()","Cover keyed collection access in tests with EXTRA_LAZY enabled"],"tags":["orm-mapping","collection","indexby","extra-lazy"],"backgroundTag":"unindexed-collection-access","analyzedSha":"d9b9ff73016bf598ae07515f97289ce8074e97a5","analyzedAt":"2026-08-21T06:13:15.863Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}