{"record":{"id":"d46b41545ffb35f6","repo":"doctrine/orm","slug":"expression-of-type-s-not-allowed-in-this-contex","errorCode":null,"errorMessage":"Expression of type '%s' not allowed in this context.","messagePattern":"Expression of type '(.+?)' not allowed in this context\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Query/Expr/Base.php","lineNumber":74,"sourceCode":"        }\n\n        return $this;\n    }\n\n    /**\n     * @param string|Stringable|null $arg\n     *\n     * @return $this\n     *\n     * @throws InvalidArgumentException\n     */\n    public function add(mixed $arg): static\n    {\n        if ($arg !== null && (! $arg instanceof self || $arg->count() > 0)) {\n            // If we decide to keep Expr\\Base instances, we can use this check\n            // @phpstan-ignore function.alreadyNarrowedType (input validation)\n            if (! is_string($arg) && ! (is_object($arg) && in_array($arg::class, $this->allowedClasses, true))) {\n                throw new InvalidArgumentException(sprintf(\n                    \"Expression of type '%s' not allowed in this context.\",\n                    get_debug_type($arg),\n                ));\n            }\n\n            $this->parts[] = $arg;\n        }\n\n        return $this;\n    }\n\n    /** @phpstan-return 0|positive-int */\n    public function count(): int\n    {\n        return count($this->parts);\n    }\n\n    public function __toString(): string","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/doctrine/orm/blob/d9b9ff73016bf598ae07515f97289ce8074e97a5/src/Query/Expr/Base.php#L56-L92","documentation":"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.","triggerScenarios":"$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.","commonSituations":"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.","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)"],"exampleFix":"// before\n$orx = $qb->expr()->orX();\n$orx->add($maybeInt); // throws for non-string\n// after\n$orx = $qb->expr()->orX();\n$orx->add((string) $maybeInt);\n// or, for comparisons:\n$orx->add($qb->expr()->eq('u.status', ':status'));","handlingStrategy":"type-guard","validationCode":"$allowed = [Comparison::class, Func::class, Orx::class, Andx::class];\nforeach ($parts as $p) {\n    if (! is_string($p) && ! (is_object($p) && in_array($p::class, $allowed, true))) { continue; }\n    $expr->add($p);\n}","typeGuard":"/** @param mixed $part */\nfunction isAllowedExprPart(mixed $part, array $allowedClasses): bool\n{\n    return is_string($part) || (is_object($part) && in_array($part::class, $allowedClasses, true));\n}","tryCatchPattern":"try { $andX->add($dynamicPart); } catch (InvalidArgumentException) { $andX->add((string) $dynamicPart); }","preventionTips":["Build expression parts with $qb->expr() factories","Cast dynamic values to string before add()","Sanitize mixed-source arrays with array_filter before addMultiple()"],"tags":["query-builder","expression","dql","type-validation"],"backgroundTag":"invalid-expression-type","analyzedSha":"d9b9ff73016bf598ae07515f97289ce8074e97a5","analyzedAt":"2026-08-21T06:13:15.863Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}