gofr-dev/gofr · error
internal server error
Error message
internal server error
What it means
errEmptyResponse is the sentinel error in pkg/gofr/http/responder.go that gofr's HTTP responder returns when a handler yields a nil/empty response that cannot be serialized into a valid HTTP reply. Rather than sending an empty body with a 200, the framework surfaces this as an 'internal server error' to the client, since it indicates the handler failed to produce any response payload.
Source
Thrown at pkg/gofr/http/responder.go:15
package http
import (
"bytes"
"encoding/json"
"errors"
"net/http"
"reflect"
"sync"
resTypes "gofr.dev/pkg/gofr/http/response"
)
var (
errEmptyResponse = errors.New("internal server error")
)
// maxRespPooledBuf caps the capacity of a response buffer returned to the pool
// so an occasional very large response does not permanently inflate every
// pooled buffer.
const maxRespPooledBuf = 64 << 10
// initialRespBufCap is the starting capacity of a freshly minted pooled buffer,
// sized to hold a typical small JSON response without a reslice.
const initialRespBufCap = 512
// respBufPool holds reusable buffers for encoding JSON response bodies. Encoding
// into a pooled buffer avoids the fresh []byte json.Marshal returns on every
// response and collapses the body + trailing newline into a single Write. A
// process-wide pool is the idiomatic shape for this and is safe for concurrent
// use by construction.
//
//nolint:gochecknoglobals // process-wide pool of reusable response-encode buffers.View on GitHub (pinned to 187eb24962)
Solutions
- Inspect the handler returning the empty response and ensure every code path returns a non-nil response object or a real error
- Log the handler name and inputs to find which route produced the empty payload
- Add unit tests (like Test_getPublicKeys) covering all return paths of the handler
- If nil is legitimate, return an explicit empty-but-non-nil response struct instead
Example fix
// before
func handler(ctx *gofr.Context) (any, error) {
if ctx.Param("id") == "" {
return nil, nil // yields internal server error
}
return data, nil
}
// after
func handler(ctx *gofr.Context) (any, error) {
if ctx.Param("id") == "" {
return emptyResponse{}, nil
}
return data, nil
} Defensive patterns
Strategy: validation
Validate before calling
resp, err := handler(ctx)
if err != nil {
return err
}
if resp == nil {
return errors.New("handler returned nil response")
} Type guard
func isNilResponse(v any) bool {
if v == nil { return true }
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Interface:
return rv.IsNil()
}
return false
} Try / catch
if resp, err := doRequest(client, url); err != nil {
if errors.Is(err, errEmptyResponse) {
log.Printf("handler produced no response: %v", err)
http.Error(w, "no content produced", http.StatusUnprocessableEntity)
return
}
return err
} Prevention
- Never return nil, nil from a gofr handler; return an explicit error or empty response struct
- Cover every branch of handlers with tests asserting a non-nil return
- Use vet/linters to catch functions with nil returns on some paths
When it happens
Trigger: A handler registered via gofr returns nil (or a zero-value interface) as its response object, so getPublicKeys/determineResponse in the responder pipeline find nothing to encode and errEmptyResponse is raised.
Common situations: Handler logic that forgets its return statement value or returns nil on an early-exit path; refactoring a handler to a typed response but leaving a nil-returning branch; middleware swallowing the response object.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- response retrieved is nil
- %w: S3 file is empty
- response writer does not support hijacking
- %w: cannot hijack connection
- response body is empty
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/1ce10042325b8dc2.
Report an issue: GitHub.