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

  1. Add a middleware or httptransport.ServerBefore RequestFunc that does ctx = context.WithValue(ctx, casbin.CasbinModelContextKey, "path/to/model.conf") before the NewEnforcer middleware runs
  2. Check middleware chaining order: the injector must be the OUTER middleware so the enforcer sees the value (endpoint.Chain(injector, casbin.NewEnforcer(...)))
  3. If you build the Enforcer yourself at startup, skip this middleware and write a custom one that compares enforcer.Enforce results instead
  4. 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

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


AI-assisted analysis of go-kit/kit@78fbbceece (2026-08-15). Data as JSON: /api/errors/c71736f9b94adbe6. Report an issue: GitHub.