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

  1. Move the value onto the element as an attribute: <one-to-many field="phonenumbers" target-entity="Phonenumber" index-by="name" />.
  2. Re-enable XSD validation (default) so invalid structures fail early with a schema error instead.
  3. 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

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


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