go
49 lines · 8 steps
How a panic-recovery middleware works in Gin
A Gin middleware that catches panics, reports them with request context, and returns a clean 500.
Explained by
highlit
1package middleware
2
3import (
4 "fmt"
5 "net/http"
6 "runtime"
7
8 "github.com/gin-gonic/gin"
9)
10
11type ErrorReporter interface {
12 CaptureException(err error, ctx map[string]interface{})
13}
14
15func Recovery(reporter ErrorReporter) gin.HandlerFunc {
16 return func(c *gin.Context) {
17 defer func() {
18 rec := recover()
19 if rec == nil {
20 return
21 }
22
23 err, ok := rec.(error)
24 if !ok {
25 err = fmt.Errorf("%v", rec)
26 }
27
28 stack := make([]byte, 8<<10)
29 stack = stack[:runtime.Stack(stack, false)]
30
31 reporter.CaptureException(err, map[string]interface{}{
32 "method": c.Request.Method,
33 "path": c.FullPath(),
34 "query": c.Request.URL.RawQuery,
35 "client_ip": c.ClientIP(),
36 "user_agent": c.Request.UserAgent(),
37 "request_id": c.GetString("request_id"),
38 "stack": string(stack),
39 })
40
41 c.Error(err) //nolint:errcheck
42 c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
43 "error": "internal server error",
44 })
45 }()
46
47 c.Next()
48 }
49}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A deferred function paired with recover() converts a panic into a normal error you can handle instead of crashing.
- 2Capturing request metadata and a stack trace at panic time makes production failures diagnosable after the fact.
- 3Aborting with a generic JSON 500 keeps internal details out of the client response while still logging the real cause.
Related explainers
rust
use axum::{ extract::{FromRef, FromRequestParts}, http::{header, request::Parts, StatusCode}, RequestPartsExt,
How a JWT extractor works in Axum
jwt
authentication
extractors
Intermediate
8 steps
go
package server import ( "net/http"
Rate limiting HTTP handlers with a token bucket
rate-limiting
token-bucket
middleware
Advanced
7 steps
go
func UploadDocument(c *gin.Context) { fileHeader, err := c.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "file is required"})
Handling multipart uploads in Gin
multipart-upload
validation
error-handling
Intermediate
9 steps
rust
use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use axum::body::Body;
A maintenance-mode gate in Axum
middleware
shared-state
atomics
Intermediate
7 steps
go
package handlers type WebhookEvent struct { ID string `json:"id"`
Verifying and processing webhooks in Gin
webhooks
hmac
idempotency
Intermediate
9 steps
javascript
const express = require('express'); const app = express();
Enforcing HTTPS with Express middleware
middleware
https
security
Intermediate
6 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-a-panic-recovery-middleware-works-in-gin-explained-go-f865/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.