doctrine/orm · error · BadMethodCallException

Selecting a collection by index is only supported on indexed

Error message

Selecting a collection by index is only supported on indexed collections.

What it means

OneToManyPersister::get() loads one element of an EXTRA_LAZY one-to-many collection by key, requiring the mapping's indexBy field to build the criteria (mappedBy = owner AND indexBy = index). With no indexBy declared, it throws BadMethodCallException instead of running an unkeyed query. Reached via PersistentCollection::get()/offsetGet() only when the collection is uninitialized and fetch is EXTRA_LAZY.

Source

Thrown at src/Persisters/Collection/OneToManyPersister.php:66

        $targetClass->isInheritanceTypeJoined()
            ? $this->deleteJoinedEntityCollection($collection)
            : $this->deleteEntityCollection($collection);
    }

    public function update(PersistentCollection $collection): void
    {
        // This can never happen. One to many can only be inverse side.
        // For owning side one to many, it is required to have a join table,
        // then classifying it as a ManyToManyPersister.
        return;
    }

    public function get(PersistentCollection $collection, mixed $index): object|null
    {
        $mapping = $this->getMapping($collection);

        if (! $mapping->isIndexed()) {
            throw new BadMethodCallException('Selecting a collection by index is only supported on indexed collections.');
        }

        $persister = $this->uow->getEntityPersister($mapping->targetEntity);

        return $persister->load(
            [
                $mapping->mappedBy  => $collection->getOwner(),
                $mapping->indexBy() => $index,
            ],
            null,
            $mapping,
            [],
            null,
            1,
        );
    }

    public function count(PersistentCollection $collection): int

View on GitHub (pinned to d9b9ff7301)

Solutions

  1. Declare indexBy: #[OneToMany(targetEntity: Comment::class, mappedBy: 'post', indexBy: 'id')]
  2. Initialize the collection before keyed access ($collection->initialize() or iterate it once)
  3. Use a repository query instead of key access for single-element lookups

Example fix

// before
#[OneToMany(targetEntity: Comment::class, mappedBy: 'post'), Fetch(FetchMode::EXTRA_LAZY)]
private Collection $comments;
$c = $post->getComments()->get(7); // throws

// after
#[OneToMany(targetEntity: Comment::class, mappedBy: 'post', indexBy: 'id'), Fetch(FetchMode::EXTRA_LAZY)]
private Collection $comments;
Defensive patterns

Strategy: validation

Validate before calling

$mapping = $em->getClassMetadata($post::class)->getAssociationMapping('comments');
if (! $mapping->isIndexed()) { $post->getComments()->initialize(); }
$comment = $post->getComments()->get($key);

Prevention

When it happens

Trigger: $children->get($key) / $children[$key] on an uninitialized EXTRA_LAZY #[OneToMany] association without `indexBy`.

Common situations: Optimizing large child collections with EXTRA_LAZY and then doing positional/keyed reads; assuming Doctrine keys collections by primary key automatically.

Related errors


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