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.

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.

Appendix: 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)