Symfony2 ESI error: File name too long
We recently came across a strange, intermittent error at OpenSky:
(36)File name too long: Cannot map GET /_internal… HTTP/1.1 to file
We use Varnish to cache large sections of our pages that include follow/unfollow buttons. If the user is following a certain curator we show the unfollow button, otherwise we show the follow button.
Our render tag looked like this:
{% render 'AppBundle:Curator:list' with
{ following: app.user.sortedFollowingSlugs }
{ standalone: true } %}
When the current user is following just a few curators this works fine. The app renders the curator list with follow/unfollow buttons accurate for the current user and Varnish caches it for us. However, when a user was following all or nearly all of our curators we see the “file name too long” error and Apache would render its 403 error template (no idea why it chooses 403 in this case).
Unpack the WTF
To understand why this happens we need to dig into how Symfony2 implements
ESI. When ESI is enabled and your app sits behind a reverse proxy that
supports ESI, any call to Twig’s {% render %} tag with the standalone
option set to true will render an <esi:include /> tag instead of rendering
the action inline. Included in the src attribute of that tag is an URL with
all the values you passed to the {% render %} tag encoded in.
The routing pattern used for the ESI URL looks like this:
/{controller}/{path}.{_format}
In the case above the {controller} value would be AppBundle:Curator:list
and the {path} value would be equivalent to the following:
php > echo http_build_query(array('following' => array('bar', 'foo')));
following%5B0%5D=bar&following%5B1%5D=foo
Now imagine what the {path} value will look like when a user is following
100+ curators. Big, right? Turns out it would be too big for Apache to handle
as a filename, which cannot exceed 255 characters, hence the “file name too
long” error.
Query String to the Rescue!
Fortunately the fix is easy and does not require any hacking on Symfony. By moving the potentially large parameter to the ESI URL’s query string our character limit jumps from 255 up to 8,190 — lots more room!
{% render 'AppBundle:Curator:list' {
standalone: true,
query: { following: app.user.sortedFollowingSlugs }
} %}
Of course you would also need to update CuratorController::listAction() to
look for the following parameter in the query string rather than in the
action arguments, but that’s an easy change.
Stay Curious
Symfony makes a lot of cool things very easy for you, but don’t become lazy. Open up the source code and figure out how it works, what technologies you’re using under the hood, and what constraints may be lurking in a dark corner somewhere, waiting to pounce.