Interpreting Go Socket Errors

Go sockets returns error variables when something goes wrong, and the different error codes are documented here in the Go documentation. However I was not able to find coherent example that would show how the error variable is supposed to be used. Canonical way seems to be just checking it against nill and dump it out in case it’s something else, like this:

n, err := conn.Read(buffer[:])
if err != nill {
    fmt.Printf("%v\n", err)
}

Real applications (especially system applications) need to branch based on error to recover properly, so just error description is not enough. I made here example what it’s possible to deduct from the error variable.

conn, err := net.Dial("tcp", "", "example.com:80")
n, err := conn.Read(buffer[:])

if err != nil {

    // print error string e.g.
    // "read tcp example.com:80: resource temporarily unavailable"
    fmt.Printf("reader %v\n", err)

    // print type of the error, e.g. "*net.OpError"
    fmt.Printf("%T", err)

    if err == os.EINVAL {
      // socket is not valid or already closed
      fmt.Println("EINVAL");
    }
    if err == os.EOF {
      // remote peer closed socket
      fmt.Println("EOF");
    }

    // matching rest of the codes needs typecasting, errno is
    // wrapped on OpError
    if e, ok := err.(*net.OpError); ok {
       // print wrapped error string e.g.
       // "os.Errno : resource temporarily unavailable"
       fmt.Printf("%T : %v\n", e.Error, e.Error)
       if e.Timeout() {
         // is this timeout error?
         fmt.Println("TIMEOUT")
       }
       if e.Temporary() {
         // is this temporary error?  True on timeout,
         // socket interrupts or when buffer is full
         fmt.Println("TEMPORARY")
       }

      // specific granular error codes in case we're interested
     switch e.Error {
        case os.EAGAIN:
           // timeout
           fmt.Println("EAGAIN")
       case os.EPIPE:
          // broken pipe (e.g. on connection reset)
          fmt.Println("EPIPE")
       default:
          // just write raw errno code, can be platform specific
          // (see syscall for definitions)
          fmt.Printf("%d\n", int64(e.Error.(os.Errno)))
     }
 }

For example in case read times out, the code would print following

read tcp 192.0.32.10:80: resource temporarily unavailable
*net.OpError
os.Errno : resource temporarily unavailable
TIMEOUT
TEMPORARY
EAGAIN

Leave a comment