go-kit/kit · error · ErrModelContextMissing
CasbinModel is required in context
Error message
CasbinModel is required in context
What it means
Sentinel error from go-kit's Casbin authorization middleware (auth/casbin/middleware.go). It means the access-control model was not present in the request context under CasbinModelContextKey when casbin.NewEnforcer(...) executed. The model (a path to a .conf model file or a casbin model.Model) is one of the two inputs casbin needs to build an Enforcer, so without it authorization cannot even be evaluated and the request aborts. In this revision the nil value is passed straight to stdcasbin.NewEnforcer; go-kit versions with an explicit nil check return this sentinel directly.
Source
Thrown at auth/casbin/middleware.go:32
// CasbinModelContextKey holds the key to store the access control model
// in context, it can be a path to configuration file or a casbin/model
// Model.
CasbinModelContextKey contextKey = "CasbinModel"
// CasbinPolicyContextKey holds the key to store the access control policy
// in context, it can be a path to policy file or an implementation of
// casbin/persist Adapter interface.
CasbinPolicyContextKey contextKey = "CasbinPolicy"
// CasbinEnforcerContextKey holds the key to retrieve the active casbin
// Enforcer.
CasbinEnforcerContextKey contextKey = "CasbinEnforcer"
)
var (
// ErrModelContextMissing denotes a casbin model was not passed into
// the parsing of middleware's context.
ErrModelContextMissing = errors.New("CasbinModel is required in context")
// ErrPolicyContextMissing denotes a casbin policy was not passed into
// the parsing of middleware's context.
ErrPolicyContextMissing = errors.New("CasbinPolicy is required in context")
// ErrUnauthorized denotes the subject is not authorized to do the action
// intended on the given object, based on the context model and policy.
ErrUnauthorized = errors.New("Unauthorized Access")
)
// NewEnforcer checks whether the subject is authorized to do the specified
// action on the given object. If a valid access control model and policy
// is given, then the generated casbin Enforcer is stored in the context
// with CasbinEnforcer as the key.
func NewEnforcer(
subject string, object interface{}, action string,
) endpoint.Middleware {
return func(next endpoint.Endpoint) endpoint.Endpoint {View on GitHub (pinned to 78fbbceece)
Solutions
- Add a middleware or httptransport.ServerBefore RequestFunc that does ctx = context.WithValue(ctx, casbin.CasbinModelContextKey, "path/to/model.conf") before the NewEnforcer middleware runs
- Check middleware chaining order: the injector must be the OUTER middleware so the enforcer sees the value (endpoint.Chain(injector, casbin.NewEnforcer(...)))
- If you build the Enforcer yourself at startup, skip this middleware and write a custom one that compares enforcer.Enforce results instead
- As a last resort pin/upgrade to a go-kit version whose nil check returns this error verbatim, to make debugging obvious
Example fix
// before: enforcer middleware mounted with no model in context
e := casbin.NewEnforcer(subject, "data1", "read")(myEndpoint)
// -> "CasbinModel is required in context"
// after: inject model+policy into context BEFORE the enforcer runs
injectCasbin := func(next endpoint.Endpoint) endpoint.Endpoint {
return func(ctx context.Context, req interface{}) (interface{}, error) {
ctx = context.WithValue(ctx, casbin.CasbinModelContextKey, "rbac_model.conf")
ctx = context.WithValue(ctx, casbin.CasbinPolicyContextKey, "rbac_policy.csv")
return next(ctx, req)
}
}
e := endpoint.Chain(injectCasbin, casbin.NewEnforcer(subject, "data1", "read"))(myEndpoint) Defensive patterns
Strategy: validation
Validate before calling
func casbinInputsPresent(ctx context.Context) error {
if ctx.Value(casbin.CasbinModelContextKey) == nil {
return casbin.ErrModelContextMissing
}
return nil
}
// call on the decorated context (e.g. inside your transport RequestFunc) before the endpoint runs Type guard
func hasCasbinModel(ctx context.Context) bool {
return ctx.Value(casbin.CasbinModelContextKey) != nil
} Try / catch
resp, err := ep(ctx, req)
if err != nil {
switch {
case errors.Is(err, casbin.ErrModelContextMissing), errors.Is(err, casbin.ErrPolicyContextMissing):
// server misconfiguration: log loudly, return 500, alert on-call
case errors.Is(err, casbin.ErrUnauthorized):
// genuine denial: return 403
}
} Prevention
- Wire context injection (model+policy) and the casbin middleware in ONE place so they cannot drift apart
- Add a startup smoke test that invokes the decorated endpoint with a fake context and asserts no context errors return
- Prefer building the casbin.Enforcer once at startup if per-request construction is not required
When it happens
Trigger: Wrapping an endpoint with casbin.NewEnforcer(subject, object, action) while nothing ever stored the model in the context: no context.WithValue(ctx, casbin.CasbinModelContextKey, "rbac_model.conf") in an HTTP RequestFunc or a preceding endpoint middleware. Also triggered by wrong ordering: the enforcer middleware mounted before (outside of) the middleware that injects the model, so the inner context value is never visible.
Common situations: Copy-pasting go-kit examples that omit the context setup; assuming NewEnforcer takes the model as a constructor argument when it must arrive via context; refactor that renamed or moved the injection middleware; running the endpoint in tests without decorating the context first.
Related errors
- CasbinPolicy is required in context
- Unauthorized Access
- token up for parsing was not passed through the context
- rate limit exceeded
- JWT was invalid
AI-assisted analysis of go-kit/kit@78fbbceece (2026-08-15).
Data as JSON: /api/errors/c71736f9b94adbe6.
Report an issue: GitHub.