You've reached the end of the line.

Ruby's EOFError class

Raised by some IO operations when reaching the end of file. Many IO methods exist in two forms,

one that returns nil when the end of file is reached, the other raises EOFError.

EOFError is a subclass of IOError.

file = File.open("/etc/hosts")
file.gets     #=> nil
file.readline #=> EOFError: end of file reached





A few of the methods that raise EOFError are:

  • IO#read_nonblock
  • IO#readline
  • IO#readpartial
  • IO#readchar
  • IO#readbyte
  • IO#sysread

There are other methods like IO#gets which don't raise EOFError even when the end of file has reached and returns nil.

» Handling it while reading files

For reading small files prefer File#read which returns the contents of the whole file instead of reading it line by line (using File#readline) to avoid running into EOFError. For larger files, use File#gets instead of File#readline.

# parse_hotels_1.rb
# read a file till the end, one line at a time
f = File.open("hotels.xml")

loop do
  rescue EOFError

The same code using File#gets, which returns a nil at the end of the file instead of raising EOFError:

# parse_hotels_2.rb
# read a file till the end, one line at a time
f = File.open("hotels.xml")

while line = f.gets do

» Handling it while reading from sockets

You have a higher chance of running into EOFError while making HTTP requests than while reading files. An EOFError while making HTTP requests can be raised even for perfect code.

A successful HTTP request has 4 main steps:

  1. Open a TCP connection to the endpoint.
  2. Send a request over the connection.
  3. Read the response written to the connection.
  4. Close the TCP connection.

In a few situations the TCP connection is closed by the server before Step 3 completes successfully:

» 1. Incorrect Request Format

This is a common error caused by an requests being sent in an incorrect format. In the following code we connect to the SSL port (443) and send a plain text HTTP GET request payload to an SSL endpoint. The server, on receiving unecrypted data (before Step 3), immediately closes the connection. Now, when our code tries to read the received response it will raise EOFError because the connection has been closed by the server.

require 'net/http'

conn = Net::HTTP.new('google.com', 443)

This can be fixed by asking Ruby to use ssl while talking to this endpoint.

require 'net/http'

conn = Net::HTTP.new('google.com', 443)
conn.use_ssl = true
resp = conn.request_get('/')

puts resp.code
# => 301
puts resp['location']
# => https://www.google.com/

» 2. Transient Network Outages

Sometimes because of transient network outages a connection can be closed before data is read from it (Step 3), when this happens your code will raise EOFError. In these situations you can retry this request if your endpoint is idempotent, and if it is not you'll have to find another way to handle it.