{"id":"7d334ecccb490d76","repo":"gin-gonic/gin","slug":"key-v-does-not-exist","errorCode":null,"errorMessage":"key %v does not exist","messagePattern":"key (.+?) does not exist","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"context.go","lineNumber":310,"sourceCode":"\n\tc.Keys[key] = value\n}\n\n// Get returns the value for the given key, ie: (value, true).\n// If the value does not exist it returns (nil, false)\nfunc (c *Context) Get(key any) (value any, exists bool) {\n\tc.mu.RLock()\n\tdefer c.mu.RUnlock()\n\tvalue, exists = c.Keys[key]\n\treturn\n}\n\n// MustGet returns the value for the given key if it exists, otherwise it panics.\nfunc (c *Context) MustGet(key any) any {\n\tif value, exists := c.Get(key); exists {\n\t\treturn value\n\t}\n\tpanic(fmt.Sprintf(\"key %v does not exist\", key))\n}\n\nfunc getTyped[T any](c *Context, key any) (res T) {\n\tif val, ok := c.Get(key); ok && val != nil {\n\t\tres, _ = val.(T)\n\t}\n\treturn\n}\n\n// GetString returns the value associated with the key as a string.\nfunc (c *Context) GetString(key any) string {\n\treturn getTyped[string](c, key)\n}\n\n// GetBool returns the value associated with the key as a boolean.\nfunc (c *Context) GetBool(key any) bool {\n\treturn getTyped[bool](c, key)\n}","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/gin-gonic/gin/blob/34dac209ffb6ef85cc78c5d217bbb7ad001d68fd/context.go#L292-L328","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use c.Get(key) and handle the exists==false case instead of MustGet when the value may legitimately be absent.","Ensure the middleware that calls c.Set runs before any handler that calls MustGet (order matters in the chain).","Use a typed accessor (c.MustGet(\"user\").(*User)) only after guaranteeing the Set, and centralise key strings as constants."],"exampleFix":"// before\nuser := c.MustGet(\"user\").(*User)\n// after\nval, ok := c.Get(\"user\")\nif !ok { c.AbortWithStatus(http.StatusUnauthorized); return }\nuser := val.(*User)","handlingStrategy":"try-catch","validationCode":"if _, ok := c.Get(\"user\"); !ok {\n    c.AbortWithStatus(http.StatusUnauthorized)\n    return\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        if s, ok := r.(string); ok && strings.HasPrefix(s, \"key \") && strings.Contains(s, \"does not exist\") {\n            c.AbortWithStatus(http.StatusInternalServerError)\n        }\n    }\n}()\nval := c.MustGet(key)","preventionTips":["Prefer c.Get over c.MustGet unless the key is guaranteed by middleware.","Order middleware so any Set runs before any MustGet.","Keep context keys in a typed constants package to avoid typos."],"tags":["context","keys","middleware","panic","go"],"analyzedSha":"34dac209ffb6ef85cc78c5d217bbb7ad001d68fd","analyzedAt":"2026-08-04T21:26:18.438Z","schemaVersion":2}