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
ManyToManyPersister::get() loads a single element of an EXTRA_LAZY many-to-many collection straight from the database by its key, which requires knowing which target field is the key (indexBy). If the association mapping has no indexBy, the persister cannot translate the key into a WHERE condition and throws BadMethodCallException. PersistentCollection::get()/offsetGet() only reach the persister when the collection is uninitialized and fetch is EXTRA_LAZY.
Source
Thrown at src/Persisters/Collection/ManyToManyPersister.php:89
$deleteTypes,
);
}
foreach ($collection->getInsertDiff() as $element) {
$this->conn->executeStatement(
$insertSql,
$this->getInsertRowSQLParameters($collection, $element),
$insertTypes,
);
}
}
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);
$mappedKey = $mapping->isOwningSide()
? $mapping->inversedBy
: $mapping->mappedBy;
assert($mappedKey !== null);
return $persister->load(
[$mappedKey => $collection->getOwner(), $mapping->indexBy() => $index],
null,
$mapping,
[],
LockMode::NONE,
1,
);
}View on GitHub (pinned to d9b9ff7301)
Solutions
- Declare indexBy in the mapping: #[ManyToMany(targetEntity: Tag::class, indexBy: 'id')] (or any unique target field)
- Drop EXTRA_LAZY for that association so get() initializes the collection in memory first
- Force initialization before access: $collection->initialize(); then $collection->get($key)
Example fix
// before #[ManyToMany(targetEntity: Tag::class), Fetch(FetchMode::EXTRA_LAZY)] private Collection $tags; $tag = $post->getTags()->get(42); // throws // after #[ManyToMany(targetEntity: Tag::class, indexBy: 'id'), Fetch(FetchMode::EXTRA_LAZY)] private Collection $tags;
Defensive patterns
Strategy: validation
Validate before calling
$mapping = $em->getClassMetadata($post::class)->getAssociationMapping('tags');
if (! $mapping->isIndexed()) {
$post->getTags()->initialize(); // fall back to in-memory keyed access
}
$tag = $post->getTags()->get($key); Prevention
- Always pair EXTRA_LAZY with indexBy when keyed access is needed
- Document the intended key field next to the association
- Test keyed reads on every EXTRA_LAZY collection
When it happens
Trigger: $collection->get($key) or $collection[$key] on an uninitialized EXTRA_LAZY many-to-many association without `indexBy` in its #[ManyToMany]/YAML/XML mapping.
Common situations: Switching an association to fetch: EXTRA_LAZY for performance and keeping array-style access; assuming collections are keyed by target primary key without declaring indexBy.
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
- Could not resolve type of column "%s" of class "%s"
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/6ef6cbe7ffed572e.
Report an issue: GitHub.