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): intView on GitHub (pinned to d9b9ff7301)
Solutions
- Declare indexBy: #[OneToMany(targetEntity: Comment::class, mappedBy: 'post', indexBy: 'id')]
- Initialize the collection before keyed access ($collection->initialize() or iterate it once)
- 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
- Add indexBy to EXTRA_LAZY one-to-many collections
- Prefer repository queries for single-child lookups
- Initialize collections before positional access
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
- This mapping is not indexed. Use %s::isIndexed() to check th
- Selecting a collection by index is only supported on indexed
- Filtering a collection by Criteria is not supported by this
- <index-by /> is not a valid tag
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/f1e7624c56cd4b70.
Report an issue: GitHub.