symfony/http-kernel · error · LogicException

Nested closures in validation groups are not supported. Use…

Error message

Nested closures in validation groups are not supported. Use a single Closure or a list of strings (or a GroupSequence) instead.

What it means

If an array of validation groups contains a Closure element, Symfony throws this LogicException: only the top-level validationGroups value may be a closure; closures nested inside a group array are not evaluated.

Solutions

  1. Move the closure to the top-level validationGroups value
  2. Replace the nested closure with the string group it computes
  3. Return only strings from the resolved groups

Example fix

// before
validationGroups: [fn() => 'Strict', 'Default']
// after
validationGroups: fn() => ['Strict', 'Default']
Defensive patterns

Strategy: validation

Validate before calling

foreach ($groups as $g) { if ($g instanceof \Closure) { throw new \InvalidArgumentException('no nested closures'); } }

Type guard

!($group instanceof \Closure)

Try / catch

try { $response = $kernel->handle($request); } catch (\LogicException $e) { if (str_contains($e->getMessage(), 'Nested closures')) { /* hoist closure to top level */ } throw $e; }

Prevention

When it happens

Trigger: Returning [fn() => 'group', 'Other'] or otherwise placing a \Closure inside the validationGroups array of a payload attribute.

Common situations: Misunderstanding that closures can be arbitrarily nested to compute individual groups; only the whole validationGroups value may be a closure.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13). Data as JSON: /api/errors/adbdbc152f33222c. Report an issue: GitHub.

Appendix: source

Thrown at Controller/ArgumentResolver/RequestPayloadValueResolver.php:349

        if ($validationGroups instanceof Expression || $validationGroups instanceof \Closure) {
            $validationGroups = $event->evaluate($validationGroups, $this->expressionLanguage);
        }

        if (null === $validationGroups || \is_string($validationGroups) || $validationGroups instanceof GroupSequence) {
            return $validationGroups;
        }

        if (!\is_array($validationGroups)) {
            throw new \LogicException('The validation groups expression or closure must return a string, an array of strings, or a GroupSequence.');
        }

        foreach ($validationGroups as $group) {
            if ($group instanceof Expression) {
                throw new \LogicException('Nested expressions in validation groups are not supported. Use a single Expression or a list of strings (or a GroupSequence) instead.');
            }

            if ($group instanceof \Closure) {
                throw new \LogicException('Nested closures in validation groups are not supported. Use a single Closure or a list of strings (or a GroupSequence) instead.');
            }

            if ($group instanceof GroupSequence) {
                throw new \LogicException('GroupSequence cannot be used inside an array of validation groups. Pass the GroupSequence as the top-level validationGroups value instead.');
            }

            if (!\is_string($group)) {
                throw new \LogicException('Validation groups must be strings.');
            }
        }

        return $validationGroups;
    }

    private static function hasNonStringScalar(array $data): bool
    {
        $stack = [$data];

View on GitHub (pinned to aa3a39d728)