doctrine/orm · error · InvalidArgumentException
<index-by /> is not a valid tag
Error message
<index-by /> is not a valid tag
What it means
In Doctrine XML mappings, index-by is an XML attribute on the <one-to-many> element (index-by="fieldName"), not a child element. If the parser finds a nested <index-by> tag, it throws InvalidArgumentException because the child form has never been valid for one-to-many collections.
Source
Thrown at src/Mapping/Driver/XmlDriver.php:419
}
if (isset($oneToManyElement['orphan-removal'])) {
$mapping['orphanRemoval'] = $this->evaluateBoolean($oneToManyElement['orphan-removal']);
}
if (isset($oneToManyElement->{'order-by'})) {
$orderBy = [];
foreach ($oneToManyElement->{'order-by'}->{'order-by-field'} ?? [] as $orderByField) {
$orderBy[(string) $orderByField['name']] = (string) ($orderByField['direction'] ?? 'ASC');
}
$mapping['orderBy'] = $orderBy;
}
if (isset($oneToManyElement['index-by'])) {
$mapping['indexBy'] = (string) $oneToManyElement['index-by'];
} elseif (isset($oneToManyElement->{'index-by'})) {
throw new InvalidArgumentException('<index-by /> is not a valid tag');
}
// Evaluate second level cache
if (isset($oneToManyElement->cache)) {
$mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($oneToManyElement->cache));
}
$metadata->mapOneToMany($mapping);
}
}
// Evaluate <many-to-one ...> mappings
if (isset($xmlRoot->{'many-to-one'})) {
foreach ($xmlRoot->{'many-to-one'} as $manyToOneElement) {
$mapping = [
'fieldName' => (string) $manyToOneElement['field'],
];
View on GitHub (pinned to d9b9ff7301)
Solutions
- Move the value onto the element as an attribute: <one-to-many field="phonenumbers" target-entity="Phonenumber" index-by="name" />.
- Re-enable XSD validation (default) so invalid structures fail early with a schema error instead.
- Validate your .dcm.xml files in CI against doctrine-mapping.xsd.
Example fix
<!-- before -->
<one-to-many field="phonenumbers" target-entity="Phonenumber">
<index-by>name</index-by>
</one-to-many>
<!-- after -->
<one-to-many field="phonenumbers" target-entity="Phonenumber" index-by="name" /> Defensive patterns
Strategy: validation
Validate before calling
// Keep XSD validation on: it rejects child <index-by> at load time. $driver = new XmlDriver($locator); // isXsdValidationEnabled = true (default) // plus CI: xmllint --noout --schema doctrine-mapping.xsd src/Entity/*.dcm.xml
Prevention
- Remember: in Doctrine XML, index-by/order-by attributes go on the element, not child tags.
- Validate all .dcm.xml files against the shipped XSD in CI.
- Prefer converting to attribute mappings to eliminate XML-shape mistakes.
When it happens
Trigger: Writing <one-to-many field="phonenumbers" target-entity="Phonenumber"><index-by>name</index-by></one-to-many> instead of putting index-by on the element itself. Happens in hand-edited or machine-converted .dcm.xml files.
Common situations: Migrating old Symfony 1 / Doctrine 1 style YAML/XML where index-by appeared as a child; XSD validation disabled so the invalid structure is not caught at load; developers copying snippet templates from old blog posts.
Related errors
- Class "%s" does not exist
- Invalid cache usage "%s"
- Uninitialized result set mapping.
- Unable to use access strategy type of [%s] without a Concurr
- Unrecognized access strategy type [%s]
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/cf2d6ce6b44b834f.
Report an issue: GitHub.