How do I fix new H18 or H13 errors that have started since switching to Router 2.0?

Issue

On the legacy router, an H18: Server Request Interrupted typically indicates that the server (aka. dyno) side of the connection closed the connection after sending back some data but not a full HTTP response. Similarly, an H13: Connection closed without response indicates that the dyno closed the connection immediately, before any data could be transferred.

The behavior in Router 2.0 is slightly different. Because Router 2.0 supports HTTP keepalives between the router and dynos, H18 or H13 may also be encountered when a dyno closes an idle connection in 1 of the 2 following ways:

  1. Gracefully, sending an RST packet back to the router. The error may be encountered because a race condition exists between the router using the connection and the dyno closing the connection. Please see the Keepalives section of our HTTP routing documentation for more details.
  2. Ungracefully, without sending back an RST packet. Without the RST packet, the router does not know the connection has closed until attempting to route the next request on that connection.

In both cases, the connection close can happen outside the handling of a request/response. The H18 or H13 will be reported by the router on the next request received.

A typical reason for the dyno to close a connection outside of request handling is due to a server-side idle timeout. Idle timeouts are common practice when building HTTP servers.

This issue is completely avoided in the legacy router because every new request gets a new connection from the router.

Resolution

Easy Solution: Disable Keepalives

The easiest way to avoid H18 or H13 noise in Router 2.0 logs is to disable HTTP keepalives between the router and the dyno:

heroku labs:enable http-disable-keepalive-to-dyno -a <app name>

Better Solution: Increase Server Idle Connection Timeout

The better solution is to increase the server's idle connection timeout to be greater than the idle connection timeout in the router (90 seconds). This is explained more in the Keepalives section of our HTTP routing documentation. Generally, keepalives improve performance as they save time spent handling connections in both the router and the dyno.

Another Recommendation

If your server does not properly implement graceful connection closes, we suggest that you utilize a server that does. This involves ensuring an RST packet is sent back to the router before the dyno closes the connection. This will allow Router 2.0 to recognize the connection as closed.

Once receiving the RST packet, any subsequent use of that connection by Router 2.0 will cause an error, internally handled. That error will prompt Router 2.0 to retry by establishing a new connection, never surfacing the internal error to the user if the re-establishment is successful.

Ask on Stack Overflow

Engage with a community of passionate experts to get the answers you need

Ask on Stack Overflow

Heroku Support

Create a support ticket and our support experts will get back to you

Contact Heroku Support