I can't figure out if I've done something silly or if I've found a bug in gorm. While I'm very well aware of what "invalid memory address or nil pointer dereference" means, I am completely mystified as to why it appears here.

In short, I call db.First() and I receive a panic for no obvious reason.

The relevant bits of my code:

package main import ( "fmt" "" "" "net/http" "os" ) type message struct { gorm.Model Title string Body string `sql:"size:0"` // blob } var db = gorm.DB{} // garbage func messageHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) m := message{} query := db.First(&m, vars["id"]) if query.Error != nil { if query.Error == gorm.RecordNotFound { notFoundHandler(w, r) return } else { fmt.Fprintf(os.Stderr, "database query failed: %v", query.Error) internalServerErrorHandler(w, r) return } } // actually do something useful } func main() { db, err := gorm.Open("sqlite3", "/tmp/gorm.db") // ... } 

db is opened in main() in the package, and is stored as a package variable. This doesn't seem very clean, but it appears to work...

The panic:

2015/07/16 20:56:12 http: panic serving [::1]:37326: runtime error: invalid memory address or nil pointer dereference goroutine 26 [running]: net/http.func·011() /usr/lib/golang/src/net/http/server.go:1130 +0xbb (*DB).First(0xd28720, 0x79f220, 0xc2080b2600, 0xc2080ef220, 0x1, 0x1, 0xd) /home/error/go/src/ +0x154 main.messageHandler(0x7f4f2e785bd8, 0xc208051c20, 0xc208035790) /home/error/go/src/myproject/messages.go:28 +0x2c1 net/http.HandlerFunc.ServeHTTP(0x9c3948, 0x7f4f2e785bd8, 0xc208051c20, 0xc208035790) /usr/lib/golang/src/net/http/server.go:1265 +0x41 (*Router).ServeHTTP(0xc2080d9630, 0x7f4f2e785bd8, 0xc208051c20, 0xc208035790) /home/error/go/src/ +0x297 net/http.serverHandler.ServeHTTP(0xc2080890e0, 0x7f4f2e785bd8, 0xc208051c20, 0xc208035790) /usr/lib/golang/src/net/http/server.go:1703 +0x19a net/http.(*conn).serve(0xc208051b80) /usr/lib/golang/src/net/http/server.go:1204 +0xb57 created by net/http.(*Server).Serve /usr/lib/golang/src/net/http/server.go:1751 +0x35e 

...where line 28 of my code is query := db.First(&m, vars["id"])

I reviewed the noted line in gorm and the First() function, but this also isn't terribly obvious.

 return newScope.Set("gorm:order_by_primary_key", "ASC"). inlineCondition(where...).callCallbacks(s.parent.callback.queries).db 

In order to figure out what might be going on, I made the following changes to my code:

First attempt: Is it complaining about being passed a string? Let's give it an integer instead. After all, the example uses an integer.

 id, _ := strconv.Atoi(vars["id"]) query := db.First(&m, id) 

Panic again, at exactly the same place.

Second attempt: Did I create my variable m the wrong way? Maybe it really needs to be allocated with new first.

 m := new(message) query := db.First(m, vars["id"]) 

Panic again, at exactly the same place.

Third attempt: I simply hardcoded the ID to be looked up, just in case gorilla/mux was misbehaving.

 m := message{} query := db.First(&m, 3) 

Panic again, at exactly the same place.

Finally, I tested with an empty database table, with a populated table requesting an ID that exists, and with a populated table requesting an ID that does not exist. In all three cases I receive the same panic.

The most interesting part of all is that apparently net/http is recovering the panic, and then my notFoundHandler() runs and I see its template output in the browser.

I am currently using the mattn/go-sqlite3 driver.

My environment is Fedora 22 x86_64 with cgo 1.4.2 as provided in Fedora RPM packages.

$ go version go version go1.4.2 linux/amd64 $ go env GOARCH="amd64" GOBIN="" GOCHAR="6" GOEXE="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home/error/go" GORACE="" GOROOT="/usr/lib/golang" GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64" CC="gcc" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0" CXX="g++" CGO_ENABLED="1" 

What's going on? Where is this panic coming from? How do I fix it?

2

2 Answers

You're shadowing your global db variable:

var db = gorm.DB{} // garbage 

Your initialisation in main() should be changed to:

var err error // Note the assignment and not initialise + assign operator db, err = gorm.Open("sqlite3", "/tmp/gorm.db") 

Otherwise, db is nil and results in the panic.

1

This occurs when a variable is nil.

in query := db.First(&m, vars["id"])

I suspect that db is nil. I do not see where you are creating it. You need to do something like:

db, err := gorm.Open("sqlite3", "/tmp/gorm.db") 

and import ""

Otherwise the db will be nil and a panic will occur.

0