gofiber/fiber · error
format handler is nil for media type
Error message
format handler is nil for media type %q at index %d
What it means
Thrown by DefaultRes.Format before any content negotiation begins, when one of the supplied ResFmt values has a nil Handler. Format validates every handler up front so that negotiation never selects a handler it cannot call. The message names the offending MediaType and the index in the handlers slice, making it a programmer-error guard, not a runtime/network condition.
Solutions
- Ensure every ResFmt passed to Format has a non-nil Handler.
- Construct ResFmt values through a helper that requires the handler, so it cannot be omitted.
- Add a unit test that asserts all handlers in the slice are non-nil before calling Format.
Example fix
// before
c.Format(
fiber.ResFmt{MediaType: "application/json"}, // Handler missing
fiber.ResFmt{MediaType: "text/html", Handler: htmlHandler},
)
// -> format handler is nil for media type "application/json" at index 0
// after
c.Format(
fiber.ResFmt{MediaType: "application/json", Handler: jsonHandler},
fiber.ResFmt{MediaType: "text/html", Handler: htmlHandler},
) Defensive patterns
Strategy: validation
Validate before calling
// Validate the handlers slice before calling Format.
func validateFormats(handlers []fiber.ResFmt) error {
for i, h := range handlers {
if h.Handler == nil {
return fmt.Errorf("handler nil at index %d (%q)", i, h.MediaType)
}
}
return nil
}
if err := validateFormats(handlers); err != nil { return err }
c.Format(handlers...) Type guard
func allFormatHandlersSet(handlers []fiber.ResFmt) bool {
for _, h := range handlers {
if h.Handler == nil { return false }
}
return true
} Try / catch
// Use a constructor that makes a nil Handler impossible to express.
func fmtJSON(h fiber.Handler) fiber.ResFmt { return fiber.ResFmt{MediaType: "application/json", Handler: h} }
c.Format(fmtJSON(jsonHandler), fmtHTML(htmlHandler)) Prevention
- Always set both MediaType and Handler in the same ResFmt literal.
- Use small constructor helpers (fmtJSON, fmtHTML) so Handler cannot be omitted.
- Add a unit test asserting all handlers are non-nil before calling Format.
- Treat this error as a bug to fix in code, not a runtime condition to catch.
When it happens
Trigger: Calling c.Format(...) with a ResFmt literal whose Handler field was omitted (left nil), e.g. ResFmt{MediaType: "application/json"} with no Handler function attached. Often a copy-paste or partial-construction mistake.
Common situations: Building the handlers slice conditionally and forgetting to set Handler on one branch; refactoring that splits MediaType and Handler assignment and drops one; a typo omitting the Handler: key in the struct literal.
Related errors
- format: at least one handler is required, but none were set
- basicauth: charset must be UTF-8
- betweenLen constraint requires two arguments
- binder: custom binder not found, please be sure to enter…
- [CORS] Invalid origin format in configuration:
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/f245c67362758a8b.
Report an issue: GitHub.
Appendix: source
Thrown at res.go:441
// formatDefaultMediaType is the sentinel MediaType marking a Format handler as
// the fallback. It is not a media type and is never emitted as a Content-Type.
const formatDefaultMediaType = "default"
// Format performs content-negotiation on the Accept HTTP header.
// It uses Accepts to select a proper format and calls the matching
// user-provided handler function.
// If no accepted format is found, and a format with MediaType "default" is given,
// that default handler is called. If no format is found and no default is given,
// StatusNotAcceptable is sent.
func (r *DefaultRes) Format(handlers ...ResFmt) error {
if len(handlers) == 0 {
return ErrNoHandlers
}
for i, h := range handlers {
if h.Handler == nil {
return fmt.Errorf("format handler is nil for media type %q at index %d", h.MediaType, i)
}
}
r.Vary(HeaderAccept)
// Absent means the combined Accept view (RFC 9110 Section 5.2) is empty:
// no field line, or a single empty one. Checked on the raw lines to skip
// the join allocation that multi-line headers would pay.
accepts := r.c.fasthttp.Request.Header.PeekAll(HeaderAccept)
if len(accepts) == 0 || (len(accepts) == 1 && len(accepts[0]) == 0) {
// Without an Accept header the client accepts any media type
// (RFC 9110 Section 12.5.1), so pick the first non-default handler and
// use its media type. The literal "default" is not a media type and
// must not be emitted as a Content-Type value.
for _, h := range handlers {
if h.MediaType != formatDefaultMediaType {
r.c.fasthttp.Response.Header.SetContentType(h.MediaType)
return h.Handler(r.c)View on GitHub (pinned to a105acad6c)