symfony/http-kernel · error · RuntimeException
Error when rendering
Error message
Error when rendering "%s" (Status code is %d).
What it means
AbstractSurrogate::handle() throws RuntimeException when the surrogate sub-request response is neither successful nor 304 Not Modified. Unlike the FragmentHandler version, no alt/ignoreErrors logic applies before the throw; the exception is caught internally only to try the alt URI.
Solutions
- Fix the src URL of the ESI/SSI tag so it returns 200/304.
- Add an alt attribute so the surrogate falls back to an alternate resource on failure.
- Add onerror="continue" to the tag to ignore failures for that include.
Example fix
// before <esi:include src="/_fragment/broken" /> // after <esi:include src="/_fragment/broken" alt="/_fragment/fallback" onerror="continue" />
Defensive patterns
Strategy: fallback
Validate before calling
// pre-check upstream URL availability if cheap: HEAD request returning 2xx/304
Try / catch
try { $content = $surrogate->handle($cache, $uri, $alt, false); } catch (\RuntimeException $e) { $content = $renderFallback(); } Prevention
- Always provide alt attributes on surrogate includes
- Use onerror="continue" for non-critical fragments
- Monitor upstream fragment endpoint health
When it happens
Trigger: An ESI/SSI include target URL returns 404/500 etc.; render() of the surrogate receives a failed Response for the embedded resource.
Common situations: Broken src attribute pointing to a removed route; upstream page erroring; permission changes making an include inaccessible.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Unable to process an ESI tag without a "src" attribute.
- 0
- Unable to process an SSI tag without a "virtual" attribute.
- Unable to create the store directory
- Passing non-scalar values as part of URI attributes to the…
AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13).
Data as JSON: /api/errors/d8d3084ae4c0bed3.
Report an issue: GitHub.
Appendix: source
Thrown at HttpCache/AbstractSurrogate.php:79
{
if (!$control = $response->headers->get('Surrogate-Control')) {
return false;
}
$pattern = \sprintf('#content="[^"]*%s/1.0[^"]*"#', strtoupper($this->getName()));
return (bool) preg_match($pattern, $control);
}
public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors): string
{
$subRequest = Request::create($uri, 'GET', [], $cache->getRequest()->cookies->all(), [], $cache->getRequest()->server->all());
try {
$response = $cache->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);
if (!$response->isSuccessful() && Response::HTTP_NOT_MODIFIED !== $response->getStatusCode()) {
throw new \RuntimeException(\sprintf('Error when rendering "%s" (Status code is %d).', $subRequest->getUri(), $response->getStatusCode()));
}
return $response->getContent();
} catch (\Exception $e) {
if ($alt) {
return $this->handle($cache, $alt, '', $ignoreErrors);
}
if (!$ignoreErrors) {
throw $e;
}
}
return '';
}
/**
* Remove the Surrogate from the Surrogate-Control header.View on GitHub (pinned to aa3a39d728)