symfony/http-kernel · error · InvalidArgumentException

Passing non-scalar values as part of URI attributes to the…

Error message

Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is not supported. Use a different rendering strategy or pass scalar values.

What it means

AbstractSurrogateFragmentRenderer falls back to the inline strategy when the request has no ESI/SSI capability. ControllerReference attributes must be embedded in a URI in that path, which only works for scalars; non-scalar attributes trigger an InvalidArgumentException.

Solutions

  1. Ensure the surrogate is configured and the request has surrogate capability (Request::setTrustedProxies + ESI listener) so URIs are generated natively.
  2. Pass only scalar attribute values, or serialize complex data (e.g. json_encode) into a scalar attribute.
  3. Use a renderer that supports non-scalar attributes, such as the inline fragment renderer directly.

Example fix

// before
$renderer->render(new ControllerReference('App::foo', [], ['filters' => ['a','b']]), $request);
// after
$renderer->render(new ControllerReference('App::foo', [], ['filters' => 'a,b']), $request);
Defensive patterns

Strategy: type-guard

Validate before calling

function hasNonScalars(array $attrs): bool {
  foreach ($attrs as $v) { if (!is_scalar($v) && $v !== null) return true; }
  return false;
}
if (hasNonScalars($ref->attributes) && !$surrogate->hasSurrogateCapability($request)) { /* flatten or skip */ }

Type guard

$allScalar = fn(array $a): bool => array_reduce($a, fn($c,$v) => $c && (is_scalar($v) || $v === null), true);

Try / catch

try { $resp = $renderer->render($uri, $request); } catch (\InvalidArgumentException $e) { $resp = $inlineRenderer->render($uri, $request); }

Prevention

When it happens

Trigger: Calling render() with a ControllerReference whose $attributes array contains arrays/objects (e.g. ['filters' => ['a','b']]) on a request without surrogate capability, causing the inline fallback path.

Common situations: Rendering ESI/SSI fragments without an ESI/SSI-capable request (no surrogate capability headers in tests); passing nested arrays or objects as fragment attributes expecting object passing like hinclude/inline.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at Fragment/AbstractSurrogateFragmentRenderer.php:61

     *
     * Additional available options:
     *
     *  * alt: an alternative URI to render in case of an error
     *  * comment: a comment to add when returning the surrogate tag
     *  * absolute_uri: whether to generate an absolute URI or not. Default is false
     *
     * Note, that not all surrogate strategies support all options. For now
     * 'alt' and 'comment' are only supported by ESI.
     *
     * @see Symfony\Component\HttpKernel\HttpCache\SurrogateInterface
     */
    public function render(string|ControllerReference $uri, Request $request, array $options = []): Response
    {
        if (!$this->surrogate || !$this->surrogate->hasSurrogateCapability($request)) {
            $request->attributes->set('_check_controller_is_allowed', true);

            if ($uri instanceof ControllerReference && $this->containsNonScalars($uri->attributes)) {
                throw new \InvalidArgumentException('Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is not supported. Use a different rendering strategy or pass scalar values.');
            }

            return $this->inlineStrategy->render($uri, $request, $options);
        }

        $absolute = $options['absolute_uri'] ?? false;

        if ($uri instanceof ControllerReference) {
            $uri = $this->generateSignedFragmentUri($uri, $request, $absolute);
        }

        $alt = $options['alt'] ?? null;
        if ($alt instanceof ControllerReference) {
            $alt = $this->generateSignedFragmentUri($alt, $request, $absolute);
        }

        $tag = $this->surrogate->renderIncludeTag($uri, $alt, $options['ignore_errors'] ?? false, $options['comment'] ?? '');

View on GitHub (pinned to aa3a39d728)