go – http: panic serving [::1]:34324: runtime error: invalid memory address or nil pointer dereference (Golang)

I am new to programming with go. While following along with a tutorial to build a web project. My goal was to display some data on a web page but I got a runtime error. I looked through the error message and I think it is coming from a handler in my handlers.go file but I’m not sure how to go about dealing with it. Any sort of help would be really appreciated

This is the error:

2022/06/01 20:47:35 http: panic serving [::1]:34324: runtime error: invalid memory address or nil pointer dereference
goroutine 50 [running]:
net/http.(*conn).serve.func1()
        /usr/local/go/src/net/http/server.go:1825 +0xbf
panic({0x770f60, 0xa72070})
        /usr/local/go/src/runtime/panic.go:844 +0x258
github.com/alexedwards/scs/v2.(*SessionManager).Put(0x79c100?, {0x864ae0, 0xc0002c10e0}, {0x7c7074, 0xb}, {0x79c100?, 0xc0002d2580})
        /home/marvell/Documents/Code/Go/pkg/mod/github.com/alexedwards/scs/v2@v2.5.0/data.go:155 +0x3b
github.com/Marvellous-Chimaraoke/bookings/internal/handlers.(*Repository).PostReservation(0xc0000ae9d8, {0x864558, 0xc0000d7680}, 0xc000167c00)
        /home/marvell/Documents/Code/Go/src/github.com/Marvellous-Chimaraoke/bookings/internal/handlers/handlers.go:144 +0x53c
net/http.HandlerFunc.ServeHTTP(0x76edc0?, {0x864558?, 0xc0000d7680?}, 0xc00029a765?)
        /usr/local/go/src/net/http/server.go:2084 +0x2f
github.com/go-chi/chi/v5.(*Mux).routeHTTP(0xc0002b4a80, {0x864558, 0xc0000d7680}, 0xc000167c00)
        /home/marvell/Documents/Code/Go/pkg/mod/github.com/go-chi/chi/v5@v5.0.7/mux.go:442 +0x216
net/http.HandlerFunc.ServeHTTP(0xc00023b5e0?, {0x864558?, 0xc0000d7680?}, 0x0?)
        /usr/local/go/src/net/http/server.go:2084 +0x2f
github.com/alexedwards/scs/v2.(*SessionManager).LoadAndSave.func1({0x8647f8, 0xc0000d0380}, 0xc000167b00)
        /home/marvell/Documents/Code/Go/pkg/mod/github.com/alexedwards/scs/v2@v2.5.0/session.go:148 +0x34d
net/http.HandlerFunc.ServeHTTP(0xc0000aca20?, {0x8647f8?, 0xc0000d0380?}, 0xc0000e0d20?)
        /usr/local/go/src/net/http/server.go:2084 +0x2f
github.com/justinas/nosurf.(*CSRFHandler).handleSuccess(...)
        /home/marvell/Documents/Code/Go/pkg/mod/github.com/justinas/nosurf@v1.1.1/handler.go:187
github.com/justinas/nosurf.(*CSRFHandler).ServeHTTP(0xc0002ce120, {0x8647f8, 0xc0000d0380}, 0xa71f40?)
        /home/marvell/Documents/Code/Go/pkg/mod/github.com/justinas/nosurf@v1.1.1/handler.go:180 +0x503
github.com/go-chi/chi/v5.(*Mux).ServeHTTP(0xc0002b4a80, {0x8647f8, 0xc0000d0380}, 0xc00032c000)
        /home/marvell/Documents/Code/Go/pkg/mod/github.com/go-chi/chi/v5@v5.0.7/mux.go:88 +0x442
net/http.serverHandler.ServeHTTP({0x863b00?}, {0x8647f8, 0xc0000d0380}, 0xc00032c000)
        /usr/local/go/src/net/http/server.go:2916 +0x43b
net/http.(*conn).serve(0xc000308000, {0x864ae0, 0xc0002c0e10})
        /usr/local/go/src/net/http/server.go:1966 +0x5d7
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:3071 +0x4db

On the web page, this is what I get:

localhost didn’t send any data.
ERR_EMPTY_RESPONSE

code from my handlers.go file:

package handlers

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"

    "github.com/Marvellous-Chimaraoke/bookings/internal/config"
    "github.com/Marvellous-Chimaraoke/bookings/internal/forms"
    "github.com/Marvellous-Chimaraoke/bookings/internal/models"
    "github.com/Marvellous-Chimaraoke/bookings/internal/render"
)

// Repository is the repository type
type Repository struct {
    App *config.AppConfig
}

// Repo is the repository used by the handlers
var Repo *Repository

// NewRepo creates a new repository
func NewRepo(a *config.AppConfig) *Repository {
    return &Repository{App: a}
}

// NewHandlers sets the repository for the handlers
func NewHandlers(r *Repository) {
    Repo = r
}

// Home is the home page handler
func (m *Repository) Home(w http.ResponseWriter, r *http.Request) {
    res := map[string]string{
        "data": "Marvellous'",
    }
    render.RenderTemplate(w, r, "home.page.tmpl", &models.TemplateData{StringMap: res})
}

// About is the about page handler
func (m *Repository) About(w http.ResponseWriter, r *http.Request) {
    // perform some logic
    stringMap := make(map[string]string)
    stringMap["test"] = "Hello world V2"

    render.RenderTemplate(w, r, "about.page.tmpl", &models.TemplateData{StringMap: stringMap})
}

// Contact renders the contact page
func (m *Repository) Contact(w http.ResponseWriter, r *http.Request) {
    render.RenderTemplate(w, r, "contact.page.tmpl", &models.TemplateData{})
}

// Generals renders the "General's Quarters" room page
func (m *Repository) Generals(w http.ResponseWriter, r *http.Request) {
    render.RenderTemplate(w, r, "generals.page.tmpl", &models.TemplateData{})
}

// Majors renders the "Major's Suite" room page
func (m *Repository) Majors(w http.ResponseWriter, r *http.Request) {
    render.RenderTemplate(w, r, "majors.page.tmpl", &models.TemplateData{})
}

// Availability renders the "search availability" page
func (m *Repository) Availability(w http.ResponseWriter, r *http.Request) {
    render.RenderTemplate(w, r, "search-availability.page.tmpl", &models.TemplateData{})
}

// PostAvailability handles form data from the "search availability" page
func (m *Repository) PostAvailability(w http.ResponseWriter, r *http.Request) {
    start := r.Form.Get("start")
    end := r.Form.Get("end")

    w.Write([]byte(fmt.Sprintf("start date is %s and end date is %s", start, end)))
}

type jsonResponse struct {
    OK      bool   `json:"ok"`
    Message string `json:"message"`
}

// AvailabilityJSON handles request for checking room availability
// and returns JSON response
func (m *Repository) AvailabilityJSON(w http.ResponseWriter, r *http.Request) {
    res := jsonResponse{
        OK:      false,
        Message: "not available!",
    }

    out, err := json.MarshalIndent(res, "", "   ")
    if err != nil {
        log.Print(err)
    }

    w.Header().Set("Content-Type", "application/json")
    w.Write(out)
}

// Reservation renders the "make reservation" page
func (m *Repository) Reservation(w http.ResponseWriter, r *http.Request) {
    var emptyReservation models.Reservation
    data := make(map[string]interface{})
    data["reservation"] = emptyReservation

    render.RenderTemplate(w, r, "make-reservation.page.tmpl", &models.TemplateData{
        Form: forms.New(nil),
        Data: data,
    })
}

// PostReservation handles post requests of reservation forms
func (m *Repository) PostReservation(w http.ResponseWriter, r *http.Request) {
    err := r.ParseForm()
    if err != nil {
        log.Println(err)
        return
    }

    reservation := models.Reservation{
        FirstName: r.Form.Get("first_name"),
        LastName:  r.Form.Get("last_name"),
        Email:     r.Form.Get("email"),
        Phone:     r.Form.Get("phone"),
    }

    form := forms.New(r.PostForm)
    form.Required("first_name", "last_name", "email")
    form.MinLength("first_name", 3, r)
    form.MinLength("last_name", 3, r)
    form.IsEmail("email")

    if !form.Valid() {
        data := make(map[string]interface{})
        data["reservation"] = reservation

        render.RenderTemplate(w, r, "make-reservation.page.tmpl", &models.TemplateData{
            Form: form,
            Data: data,
        })
        return
    }

    m.App.Session.Put(r.Context(), "reservation", reservation)
    http.Redirect(w, r, "/reservation-summary", http.StatusSeeOther)
}

// ReservationSummary displays a summary of user's reservation details
func (m *Repository) ReservationSummary(w http.ResponseWriter, r *http.Request) {
    reservation, ok := m.App.Session.Get(r.Context(), "reservation").(models.Reservation)
    if !ok {
        log.Println("cannot get item from session")
        return
    }

    data := make(map[string]interface{})
    data["reservation"] = reservation

    render.RenderTemplate(w, r, "reservation-summary.page.tmpl", &models.TemplateData{
        Data: data,
    })
}

Leave a Comment