doctrine/orm · error · LogicException

This mapping is not indexed. Use %s::isIndexed() to check th

Error message

This mapping is not indexed. Use %s::isIndexed() to check that before calling %s.

What it means

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.

Source

Thrown at src/Mapping/ToManyAssociationMappingImplementation.php:44

     */
    public array $orderBy = [];

    /** @return array<string, 'asc'|'desc'> */
    final public function orderBy(): array
    {
        return $this->orderBy;
    }

    /** @phpstan-assert-if-true !null $this->indexBy */
    final public function isIndexed(): bool
    {
        return $this->indexBy !== null;
    }

    final public function indexBy(): string
    {
        if (! $this->isIndexed()) {
            throw new LogicException(sprintf(
                'This mapping is not indexed. Use %s::isIndexed() to check that before calling %s.',
                self::class,
                __METHOD__,
            ));
        }

        return $this->indexBy;
    }

    /** @return list<string> */
    public function __sleep(): array
    {
        $serialized = parent::__sleep();

        if ($this->indexBy !== null) {
            $serialized[] = 'indexBy';
        }

View on GitHub (pinned to d9b9ff7301)

Solutions

  1. Add indexBy to the association mapping: #[ManyToMany(targetEntity: Tag::class, indexBy: 'slug')] or indexBy on #[OneToMany]
  2. Check $mapping->isIndexed() before calling indexBy()
  3. If indexing is not intended, iterate the collection instead of key access

Example fix

// before
#[ManyToMany(targetEntity: Tag::class)]
private Collection $tags;
$tag = $article->getTags()->get('php'); // throws

// after
#[ManyToMany(targetEntity: Tag::class, indexBy: 'slug')]
private Collection $tags;
$tag = $article->getTags()->get('php');
Defensive patterns

Strategy: validation

Validate before calling

$mapping = $em->getClassMetadata($owner::class)->getAssociationMapping($field);
if ($mapping->isIndexed()) { $key = $mapping->indexBy(); }

Prevention

When it happens

Trigger: 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).

Common situations: 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]).

Related errors


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