How to correctly check io.Reader for nil?

Issue

If you create a variable of type bytes.Buffer (without initialization) and assign it to a field of type io.Reader, then after checking io.Reader for nil there will be an error: invalid memory address or nil pointer dereference. How to check this correctly to avoid such errors?

Playground

package main

import (
    "bytes"
    "io"
    "io/ioutil"
)

type Request struct {
    Body io.Reader
}

func main() {
    var data *bytes.Buffer

    request := &Request{
        Body: data,
    }

    if request.Body != nil {
        ioutil.ReadAll(request.Body) // panic: runtime error: invalid memory address or nil pointer dereference
    }
}

Solution

To check if an io.Reader (or any other interface) value is nil, you simply compare it to nil.

Whether a non-nil io.Reader is a meaningful implementation, that’s another question.

E.g. is this implementation meaningful?

type panicReader struct{}

func (panicReader) Read(p []byte) (int, error) {
    panic("foo")
}

panicReader certainly implements io.Reader, but whenever you call its Read() method, it will always panic.

There is bytes.Buffer. A pointer to it implements io.Reader. But calling Read() on a nil *bytes.Buffer pointer value will panic.

You can’t make a general conclusion here. See this io.Reader implementation:

type myBuffer struct{}

var count int

func (*myBuffer) Read(p []byte) (int, error) {
    if len(p) > 0 {
        count++
        if count >= 10 {
            return 0, io.EOF
        }
        p[0] = 'a'
        return 1, nil
    }
    return 0, nil
}

*myBuffer implements io.Reader, and its Read() method does not use the pointer receiver value. What does this mean? You can call Read() on a nil *myBuffer value:

var data *myBuffer

request := &Request{
    Body: data,
}

if request.Body != nil {
    data, err := ioutil.ReadAll(request.Body)
    fmt.Println(string(data), err)
}

This will output (try it on the Go Playground):

aaaaaaaaa <nil>

See related question:

Hiding nil values, understanding why Go fails here

Go reflection with interface embedded in struct – how to detect "real" functions?

Answered By – icza

Answer Checked By – Jay B. (GoLangFix Admin)

Leave a Reply

Your email address will not be published.