doctrine/orm · error · InvalidArgumentException
Expression of type '%s' not allowed in this context.
Error message
Expression of type '%s' not allowed in this context.
What it means
Expr\Base::add() underpins the expression classes used by QueryBuilder (Andx, Orx, Select, OrderBy, GroupBy). An argument must be a string or an instance of one of the subclass's allowedClasses — Andx/Orx accept Comparison, Func and each other, Select accepts only Func, OrderBy/GroupBy accept only strings. Any other value (ints, bools, arbitrary objects, even Stringable objects) throws InvalidArgumentException.
Source
Thrown at src/Query/Expr/Base.php:74
}
return $this;
}
/**
* @param string|Stringable|null $arg
*
* @return $this
*
* @throws InvalidArgumentException
*/
public function add(mixed $arg): static
{
if ($arg !== null && (! $arg instanceof self || $arg->count() > 0)) {
// If we decide to keep Expr\Base instances, we can use this check
// @phpstan-ignore function.alreadyNarrowedType (input validation)
if (! is_string($arg) && ! (is_object($arg) && in_array($arg::class, $this->allowedClasses, true))) {
throw new InvalidArgumentException(sprintf(
"Expression of type '%s' not allowed in this context.",
get_debug_type($arg),
));
}
$this->parts[] = $arg;
}
return $this;
}
/** @phpstan-return 0|positive-int */
public function count(): int
{
return count($this->parts);
}
public function __toString(): stringView on GitHub (pinned to d9b9ff7301)
Solutions
- Cast scalars/objects to string: ->add((string) $value) for raw DQL fragments
- Build conditions with the factory: $qb->expr()->eq('u.id', ':id') produces a Comparison accepted by andX()
- Match the expression class to its allowed types — only strings for OrderBy/GroupBy, Func for Select
- Filter input arrays before addMultiple(): array_filter($parts, is_string(...) || instanceof allowed)
Example fix
// before
$orx = $qb->expr()->orX();
$orx->add($maybeInt); // throws for non-string
// after
$orx = $qb->expr()->orX();
$orx->add((string) $maybeInt);
// or, for comparisons:
$orx->add($qb->expr()->eq('u.status', ':status')); Defensive patterns
Strategy: type-guard
Validate before calling
$allowed = [Comparison::class, Func::class, Orx::class, Andx::class];
foreach ($parts as $p) {
if (! is_string($p) && ! (is_object($p) && in_array($p::class, $allowed, true))) { continue; }
$expr->add($p);
} Type guard
/** @param mixed $part */
function isAllowedExprPart(mixed $part, array $allowedClasses): bool
{
return is_string($part) || (is_object($part) && in_array($part::class, $allowedClasses, true));
} Try / catch
try { $andX->add($dynamicPart); } catch (InvalidArgumentException) { $andX->add((string) $dynamicPart); } Prevention
- Build expression parts with $qb->expr() factories
- Cast dynamic values to string before add()
- Sanitize mixed-source arrays with array_filter before addMultiple()
When it happens
Trigger: $expr->andX()->add(new \DateTimeImmutable()) or ->add(123); passing an Expr\OrderBy or a plain stringable value object into Andx/Orx; passing a Comparison into OrderBy::add(); feeding expr parts from untrusted/mixed-typed arrays.
Common situations: Dynamically assembled filters where a null/int sneaks into addMultiple(); assuming __toString objects are accepted (they are not); mixing QueryBuilder expression objects into the wrong expression type.
Related errors
- No alias was set before invoking getRootAlias().
- {argAlias} does not exist
- The hint "HINT_CACHE_EVICT" is not valid for select statemen
- Undefined reference field mapping "%s"
- Unable to resolve the reference field mapping "%s"
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/d46b41545ffb35f6.
Report an issue: GitHub.