Skip to content

Errno::EPIPE / Errno::ECONNRESET in accept loop logged as unhandled exceptions #333

@thomaswitt

Description

@thomaswitt

When a client disconnects mid-response (e.g. browser navigation, WebSocket teardown, load-balancer health-check timeout), Falcon::Server#accept raises Errno::EPIPE or Errno::ECONNRESET. These bubble up through the Async task runner and are logged as: "Task may have ended with unhandled exception."

These are expected, harmless disconnects, but they flood logs with false alarms.

Reproduction

  1. Start a Falcon-based Rails app
  2. Use Turbo Drive to navigate between pages quickly (or let an ALB health-check timeout)
  3. Observe console output:
Task may have ended with unhandled exception.
Errno::ECONNRESET: Connection reset by peer

This is particularly noisy with Hotwire/Turbo Drive, where every client-side navigation aborts the
previous response.

Current workaround

We monkey-patch Falcon::Server#accept to swallow only these two specific errors:

class Falcon::Server
  alias_method :__original_accept, :accept

  def accept(...)
    __original_accept(...)
  rescue Errno::EPIPE, Errno::ECONNRESET
    # Client disconnected mid-response — expected.
  end
end

Suggested fix

Handle Errno::EPIPE and Errno::ECONNRESET inside Falcon::Server#accept (or the connection task it spawns). These are not actionable errors — the client is simply gone. Something like:

def accept(...)
  @accept_count += 1
  @connection_count += 1

  super
rescue Errno::EPIPE, Errno::ECONNRESET
  # Client disconnected — nothing to do.
ensure
  @connection_count -= 1
end

All other exceptions would still propagate normally.

Or maybe intrduce a configuration switch whether to warn about these kind of errors

Environment

  • Falcon: 0.54.0
  • async-http: 0.94.2
  • Ruby: 3.4.x

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions