crowdsecurity/crowdsec · error
bouncer not found
Error message
bouncer not found
What it means
getBouncerFromContext extracts the authenticated bouncer (*ent.Bouncer) that the JWT/auth middleware stored in the gin context under middlewares.BouncerContextKey. It returns "bouncer not found" when the key is absent entirely, meaning the request reached a bouncer-only endpoint without having gone through the bouncer authentication middleware. Callers such as GetDecision, StreamDecision and the usage metrics handlers abort with 401 when this happens.
Source
Thrown at pkg/apiserver/controllers/v1/utils.go:19
package v1
import (
"errors"
"net"
"net/http"
"strings"
jwt "github.com/appleboy/gin-jwt/v2"
"github.com/gin-gonic/gin"
middlewares "github.com/crowdsecurity/crowdsec/pkg/apiserver/middlewares/v1"
"github.com/crowdsecurity/crowdsec/pkg/database/ent"
)
func getBouncerFromContext(ctx *gin.Context) (*ent.Bouncer, error) {
bouncerInterface, exist := ctx.Get(middlewares.BouncerContextKey)
if !exist {
return nil, errors.New("bouncer not found")
}
bouncerInfo, ok := bouncerInterface.(*ent.Bouncer)
if !ok {
return nil, errors.New("bouncer not found")
}
return bouncerInfo, nil
}
func isUnixSocket(c *gin.Context) bool {
if localAddr, ok := c.Request.Context().Value(http.LocalAddrContextKey).(net.Addr); ok {
return strings.HasPrefix(localAddr.Network(), "unix")
}
return false
}
View on GitHub (pinned to 909b515798)
Solutions
- Ensure the bouncer authentication middleware (apikey/TLS) is registered on the route before the handler so it sets middlewares.BouncerContextKey
- Register the bouncer with `cscli bouncers add <name>` and send the returned API key as the X-Api-Key header
- In tests, set ctx.Set(middlewares.BouncerContextKey, &ent.Bouncer{...}) before invoking the handler
- Check API server logs for an earlier middleware failure that skipped context population
Example fix
// before: route without auth
group.GET("/decisions", ctrl.GetDecision)
// after: route with bouncer auth middleware
group.GET("/decisions", mw.BouncerAuth, ctrl.GetDecision) Defensive patterns
Strategy: try-catch
Validate before calling
if _, ok := c.Get(middlewares.BouncerContextKey); !ok {
c.AbortWithStatusJSON(401, gin.H{"message": "authenticate first"})
return
} Type guard
v, exists := c.Get(middlewares.BouncerContextKey)
bouncer, ok := v.(*ent.Bouncer)
if !exists || !ok || bouncer == nil { /* unauthenticated */ } Try / catch
bouncer, err := getBouncerFromContext(c)
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "bouncer not found"})
return
} Prevention
- Always register the apikey/TLS bouncer middleware before bouncer-facing handlers
- When testing handlers, seed the gin context with middlewares.BouncerContextKey
- Register bouncers with cscli bouncers add and send X-Api-Key on every request
When it happens
Trigger: An HTTP request hits /v1/decisions, /v1/decision/stream, or the Prometheus/usage-metrics bouncer endpoints without the middleware having authenticated a bouncer — e.g. the route is mounted without the bouncer auth middleware, a test constructs the gin context directly without setting middlewares.BouncerContextKey, or the middleware failed but did not abort before the handler ran.
Common situations: Custom reverse-proxy setups that strip or bypass the API-key auth step; integration tests that call handlers with a bare gin test context; misconfigured LAPI where tls auth or api-key auth silently failed; calling internal handler functions directly from other code.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- invalid token for auto registration
- IP not in allowed range for auto registration
- failed to extract claims
- tls authentication required
- authenticate watcher (%s): %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/9d81b5583d179c89.
Report an issue: GitHub.