gin-gonic/gin · critical

key %v does not exist

Error message

key %v does not exist

What it means

Context.MustGet (context.go:310) panics with this message when the requested key is not present in c.Keys. Unlike Get (which returns ok=false), MustGet is designed for mandatory values and intentionally panics to surface programmer error; recovery middleware will turn it into a 500 unless intercepted.

Source

Thrown at context.go:310

	c.Keys[key] = value
}

// Get returns the value for the given key, ie: (value, true).
// If the value does not exist it returns (nil, false)
func (c *Context) Get(key any) (value any, exists bool) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	value, exists = c.Keys[key]
	return
}

// MustGet returns the value for the given key if it exists, otherwise it panics.
func (c *Context) MustGet(key any) any {
	if value, exists := c.Get(key); exists {
		return value
	}
	panic(fmt.Sprintf("key %v does not exist", key))
}

func getTyped[T any](c *Context, key any) (res T) {
	if val, ok := c.Get(key); ok && val != nil {
		res, _ = val.(T)
	}
	return
}

// GetString returns the value associated with the key as a string.
func (c *Context) GetString(key any) string {
	return getTyped[string](c, key)
}

// GetBool returns the value associated with the key as a boolean.
func (c *Context) GetBool(key any) bool {
	return getTyped[bool](c, key)
}

View on GitHub (pinned to 34dac209ff)

Solutions

  1. Use c.Get(key) and handle the exists==false case instead of MustGet when the value may legitimately be absent.
  2. Ensure the middleware that calls c.Set runs before any handler that calls MustGet (order matters in the chain).
  3. Use a typed accessor (c.MustGet("user").(*User)) only after guaranteeing the Set, and centralise key strings as constants.

Example fix

// before
user := c.MustGet("user").(*User)
// after
val, ok := c.Get("user")
if !ok { c.AbortWithStatus(http.StatusUnauthorized); return }
user := val.(*User)
Defensive patterns

Strategy: try-catch

Validate before calling

if _, ok := c.Get("user"); !ok {
    c.AbortWithStatus(http.StatusUnauthorized)
    return
}

Try / catch

defer func() {
    if r := recover(); r != nil {
        if s, ok := r.(string); ok && strings.HasPrefix(s, "key ") && strings.Contains(s, "does not exist") {
            c.AbortWithStatus(http.StatusInternalServerError)
        }
    }
}()
val := c.MustGet(key)

Prevention

When it happens

Trigger: Calling c.MustGet("user") when no prior middleware did c.Set("user", ...); typo in the key ("User" vs "user"); calling MustGet before the middleware that sets it in the chain; key set under a different type (e.g. *User vs User) but that returns nil not panic.

Common situations: Auth middleware ordering (MustGet called before Set runs); refactoring a key name in one place but not another; conditional Set that skipped on an early Abort.

Related errors


AI-assisted analysis of gin-gonic/gin@34dac209ff (2026-08-04). Data as JSON: /data/errors/7d334ecccb490d76.json. Report an issue: GitHub.