doctrine/orm · error · RuntimeException
No alias was set before invoking add().
Error message
No alias was set before invoking add().
What it means
add('join', $parts) expects an array keyed by the alias the joins belong to; numeric keys are deprecated and get remapped to the builder's first root alias. That remapping throws RuntimeException when the builder has no root aliases at all, because there is no alias to attribute the joins to.
Source
Thrown at src/QueryBuilder.php:653
if (is_array($dqlPart) && $dqlPartName !== 'join') {
$dqlPart = reset($dqlPart);
}
if ($dqlPartName === 'join') {
$newDqlPart = [];
foreach ($dqlPart as $k => $v) {
if (is_numeric($k)) {
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/12051',
'Using numeric keys in %s for join parts is deprecated and will not be supported in 4.0. Use an associative array with the root alias as key instead.',
__METHOD__,
);
$aliases = $this->getRootAliases();
if (! isset($aliases[0])) {
throw new RuntimeException('No alias was set before invoking add().');
}
$k = $aliases[0];
}
$newDqlPart[$k] = $v;
}
$dqlPart = $newDqlPart;
}
if ($append && $isMultiple) {
if (is_array($dqlPart)) {
$key = key($dqlPart);
$this->dqlParts[$dqlPartName][$key][] = $dqlPart[$key];
} else {
$this->dqlParts[$dqlPartName][] = $dqlPart;View on GitHub (pinned to d9b9ff7301)
Solutions
- Pass the associative form keyed by the root alias: $qb->add('join', ['u' => $joinExpr]).
- Call from(User::class, 'u') before add('join', ...) so even the deprecated numeric form has a root to map to.
- When copying parts between builders, copy 'from' first, then 'join'.
Example fix
// before
$target->add('join', [$sourceJoinExpr]); // numeric key + no root alias -> RuntimeException
// after
$target->from(User::class, 'u');
$target->add('join', ['u' => $sourceJoinExpr]); Defensive patterns
Strategy: validation
Validate before calling
if ($qb->getRootAliases() === []) {
throw new LogicException("Add from() before add('join', ...): joins need a root alias.");
}
$qb->add('join', ['u' => $joinExpr]); // associative key avoids the deprecated numeric path Try / catch
Catch \Doctrine\ORM\RuntimeException in generic part-copy code and rethrow, including both builders' root aliases in the message.
Prevention
- Always key join arrays by the root alias, never by index.
- Copy 'from' before 'join' when merging builders.
- Watch for the numeric-key deprecation notice: it is the early warning for this exception.
When it happens
Trigger: $qb->add('join', [$joinExpr]) (numeric list) on a builder with no from() yet; copying one builder's join parts into a fresh builder whose root has not been added; numeric-string keys like '0' also match the is_numeric remap path and emit the deprecation notice.
Common situations: Builder merge/clone utilities moving getDQLPart('join') arrays between builders; code written against ORM 2's numeric join arrays; filter bundles appending joins before the base query assembles its from part.
Related errors
- No alias was set before invoking getRootAlias().
- Using $append = true does not have an effect with 'where' or
- Setting a limit is not supported for delete or update querie
- %s(): The alias for entity %s must not be omitted.
- Uninitialized result set mapping.
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/80c224c29dbb88eb.
Report an issue: GitHub.