Issue #21642 has been updated by ioquatix (Samuel Williams). Thanks for your feedback. I understand your point and I think it makes sense. "Connection Reset" and "Broken Pipe" have well defined meanings. On the face of it, I don't know what "CloseUnrecoverable" means. Is there a concept like this in other languages? - "Connection Reset" occurs during read, and indicates that the remote end has dropped the connection, and it's likely that we are missing data (as opposed to reaching end of stream). - "Broken Pipe" occurs during write, and indicates the remote end is no longer accepting more data. Broken pipe doesn't mean you can't read more data. So there are subtle differences. Modules like `IO::BrokenPipe` and `IO::ConnectionReset` might be suitable, but maybe they are too specific? A lot of UNIXisms are overly specific (like `UNIXSocket` on Windows doesn't really make sense). If you felt like having a concept for "The connection has failed in an unrecoverable way, perhaps `module IO::StreamFailed`. Regarding OpenSSL, there are many places in OpenSSL that raise `SSLError`, so I think what you are suggesting is this: ```ruby class SSLReadError < SSLError include IO::ConnectionReset end ``` Is it sufficiently compatible? My main issue is not that we need to introduce shared concepts, it's that OpenSSL does not implement a compatible interface to `IO#read` and `IO#write`. But I think expecting OpenSSL to raise `Errno::EPIPE` and `Errno::ECONNRESET` is also unrealistic/incorrect. ---------------------------------------- Feature #21642: Introduce `IO::ConnectionResetError` and `IO::BrokenPipeError` as standardized IO-level exceptions. https://bugs.ruby-lang.org/issues/21642#change-114871 * Author: ioquatix (Samuel Williams) * Status: Open ---------------------------------------- Currently, different IO implementations in Ruby raise inconsistent exception types when a connection is reset or broken. For example: ```ruby # Plain TCP socket: socket.read_nonblock(1024) # => Errno::ECONNRESET # SSL socket: ssl_socket.read_nonblock(1024) # => OpenSSL::SSL::SSLError: SSL_read: unexpected eof while reading ``` Both represent a *connection reset by peer*, but the errors differ significantly in type and message. This inconsistency makes it difficult to handle connection-level errors generically across IO types. Similarly, `EPIPE` is used in some contexts to signal a *broken connection*, but again, the representation and message differ between IO classes. ### Proposal Introduce explicit subclasses of the corresponding system errors as part of Ruby’s standard IO interface: ```ruby class IO class ConnectionResetError < Errno::ECONNRESET; end class BrokenPipeError < Errno::EPIPE; end end ``` Then, standardize the Ruby I/O ecosystem (including OpenSSL) to raise these subclasses instead of raw system errors or library-specific error wrappers. This would establish a consistent, well-defined public interface for handling connection-level failures. ### Motivation * **Consistency:** Users can handle `IO::ConnectionResetError` across `IO`, `TCPSocket`, `OpenSSL::SSL::SSLSocket`, and other IO-like objects. * **Clarity:** The name clearly expresses a high-level semantic (“connection reset”) rather than a low-level system error. * **Extensibility:** Other Ruby IO implementations (custom sockets, pipes, etc.) can follow the same convention. * **Backwards Compatibility:** Because `IO::ConnectionResetError < Errno::ECONNRESET`, existing rescue clauses continue to work: ```ruby rescue Errno::ECONNRESET # still catches it end ``` ### Examples ```ruby begin io.read_nonblock(1024) rescue IO::ConnectionResetError puts "Connection was reset by peer." end ``` ### Impact on existing code * Minimal to none. * Existing code that rescues `Errno::ECONNRESET` or `Errno::EPIPE` will continue to function. * Future code gains a more semantic and portable way to handle these common failure modes. -- https://bugs.ruby-lang.org/