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

  1. Ensure the bouncer authentication middleware (apikey/TLS) is registered on the route before the handler so it sets middlewares.BouncerContextKey
  2. Register the bouncer with `cscli bouncers add <name>` and send the returned API key as the X-Api-Key header
  3. In tests, set ctx.Set(middlewares.BouncerContextKey, &ent.Bouncer{...}) before invoking the handler
  4. 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

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


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/9d81b5583d179c89. Report an issue: GitHub.