doctrine/orm · error · LogicException
{argAlias} does not exist
Error message
{argAlias} does not exist What it means
LogicException from AbstractHydrator row processing (src/Internal/Hydration/AbstractHydrator.php:372) during hydration of `NEW` expressions in DQL (SELECT new DTO(...)). For nested new-object arguments, the hydrator looks up each argument's DQL alias either among collected new objects or row data; when an alias appears in neither, this 'X does not exist' is thrown — the SELECT list references an alias that produced no data in the row.
Source
Thrown at src/Internal/Hydration/AbstractHydrator.php:372
}
}
$nestedEntities = [];
/**@var string $argAlias */
foreach ($this->resultSetMapping()->nestedNewObjectArguments as ['ownerIndex' => $ownerIndex, 'argIndex' => $argIndex, 'argAlias' => $argAlias]) {
if (array_key_exists($argAlias, $rowData['newObjects'])) {
ksort($rowData['newObjects'][$argAlias]['args']);
$rowData['newObjects'][$ownerIndex]['args'][$argIndex] = $rowData['newObjects'][$argAlias]['class']->newInstanceArgs($rowData['newObjects'][$argAlias]['args']);
unset($rowData['newObjects'][$argAlias]);
} elseif (array_key_exists($argAlias, $rowData['data'])) {
if (! array_key_exists($argAlias, $nestedEntities)) {
$nestedEntities[$argAlias] = '';
$rowData['data'][$argAlias] = $this->hydrateNestedEntity($rowData['data'][$argAlias], $argAlias);
}
$rowData['newObjects'][$ownerIndex]['args'][$argIndex] = $rowData['data'][$argAlias];
} else {
throw new LogicException($argAlias . ' does not exist');
}
}
foreach (array_keys($nestedEntities) as $entity) {
unset($rowData['data'][$entity]);
}
foreach ($rowData['newObjects'] as $objIndex => $newObject) {
ksort($rowData['newObjects'][$objIndex]['args']);
$obj = $rowData['newObjects'][$objIndex]['class']->newInstanceArgs($rowData['newObjects'][$objIndex]['args']);
$rowData['newObjects'][$objIndex]['obj'] = $obj;
}
return $rowData;
}
/** @param mixed[] $data pre-hydrated SQL Result Row. */View on GitHub (pinned to d9b9ff7301)
Solutions
- Make sure every alias used as a NEW-expression argument is itself part of the SELECT list (SELECT new DTO(a.name), a FROM ... JOIN ...).
- Flatten nested NEW expressions: select the inner new object alias explicitly, or build the nested object in PHP after hydrating the outer DTO.
- Remove HINT_FORCE_PARTIAL_LOAD / partial-object hints on that query and retest — partial hydration can drop the data key the alias needs.
- If the DQL is minimal and valid, reproduce on the latest patch release and report to doctrine/orm ( hydration LogicException 'alias does not exist').
Example fix
/* before: alias a is only used as a nested NEW argument, never selected */ SELECT new UserDTO(new NameDTO(u.firstName, u.lastName), a) FROM App\Entity\User u JOIN u.address a /* after: select the joined alias so the row contains its data */ SELECT new UserDTO(new NameDTO(u.firstName, u.lastName), a) FROM App\Entity\User u JOIN u.address a -- keep, but hydrate a explicitly if still missing: -- or: SELECT u, a FROM ... then map to DTO in PHP
Defensive patterns
Strategy: try-catch
Validate before calling
// Before running, sanity-check that every alias used in NEW(...) args appears in the SELECT list
$select = 'SELECT new DTO(new Inner(u.id), a) FROM App\\Entity\\User u JOIN u.address a';
// ensure 'a' is selected/mapped; simplest static guard:
foreach (['u', 'a'] as $alias) {
if (! preg_match('/\b' . $alias . '\b/', $select)) {
throw new LogicException("Alias {$alias} used in NEW() but absent from SELECT");
}
} Try / catch
try {
$dtos = $query->getResult();
} catch (\LogicException $e) {
// 'X does not exist': NEW-expression alias produced no row data.
// Fall back to hydrating entities/scalars and constructing DTOs in PHP.
$rows = $em->createQuery('SELECT u, a FROM App\\Entity\\User u JOIN u.address a')->getResult();
$dtos = array_map(static fn ([$u, $a]) => new UserDTO(NameDTO::from($u), $a), $rows);
} Prevention
- Keep NEW() argument aliases identical to aliases actually present in the SELECT clause.
- Prefer flat NEW expressions or manual DTO mapping for structures with nested joined arguments.
- Pin regression tests around DTO queries so ORM upgrades re-verify nested NEW hydration.
When it happens
Trigger: DQL using NEW-object syntax where a nested argument alias is not (effectively) selected or mapped: e.g. SELECT new DTO(new Inner(u.id), a) ... where alias 'a' was joined but not selected, was pruned by the SQL walker, or the argument is a bare alias the parser recorded in nestedNewObjectArguments while the row contains no such key. Typical shapes: nested NEW expressions over joined entities, NEW combined with partial selects/HINT_FORCE_PARTIAL_LOAD, or scalar aliases reused across NEW arguments.
Common situations: DTO refactoring where someone moved an association into a nested new-expression but forgot to keep the alias in the SELECT; mixing NEW DTO(...) with joins whose aliases are only used inside the NEW argument; edge-case ORM versions where nested new-object arguments over joined aliases are incompletely supported — if the DQL looks legitimate, it may be an ORM bug worth reporting with a reproducer.
Related errors
- hydrateRowData() not implemented by this hydrator.
- Attempting to change readonly property %s::$%s.
- No metadata for DQL alias: %s
- No alias was set before invoking getRootAlias().
- Not all identifier properties can be found in the ResultSetM
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/1993b404673d935b.
Report an issue: GitHub.