weaviate/weaviate · critical

RBAC is expected to be enabled, but the controller wasn't in

Error message

RBAC is expected to be enabled, but the controller wasn't initialized

What it means

A startup sanity check in configureAuthorizer: RBAC is enabled in config but `appState.RBAC` was never assigned, meaning the rbac.New branch either didn't run or failed to assign the controller. Weaviate treats this as an invariant violation and refuses to start, because serving requests with RBAC enabled but no enforcer would silently bypass authorization.

Source

Thrown at adapters/handlers/rest/configure_server.go:190

			appState.NamespacesController,
			appState.Logger)
		if err != nil {
			return fmt.Errorf("can't init casbin %w", err)
		}

		appState.AuthzController = rbacController
		appState.RBAC = rbacController
		appState.Authorizer = rbacController
	} else if appState.ServerConfig.Config.Authorization.AdminList.Enabled {
		appState.Authorizer = adminlist.New(appState.ServerConfig.Config.Authorization.AdminList)
	} else {
		appState.Authorizer = &authorization.DummyAuthorizer{}
	}

	if appState.ServerConfig.Config.Authorization.Rbac.Enabled && appState.RBAC == nil {
		// this in general shall not happen, it's to catch cases were RBAC expected but we weren't able
		// to assign it.
		return fmt.Errorf("RBAC is expected to be enabled, but the controller wasn't initialized")
	}

	return nil
}

func timeTillDeadline(ctx context.Context) string {
	dl, _ := ctx.Deadline()
	return time.Until(dl).String()
}

View on GitHub (pinned to 75aa4b6d11)

Solutions

  1. Look for a preceding "can't init casbin" error in the logs; fix that root cause — this guard is its downstream symptom.
  2. Confirm `authorization.rbac.enabled` matches intent; if you meant admin-list or no auth, correct the config.
  3. Ensure the RBAC controller assignment (appState.RBAC = rbacController) executes on every path where RBAC is enabled; rebuild from an unmodified release.
  4. If reproducible on a stock build, report with full startup logs and config (redact secrets).

Example fix

// before: enabled RBAC while pointing admin list on, masking the rbac branch
authorization:
  rbac: { enabled: true }
  admin_list: { enabled: true, users: [...] }
// after: single coherent authorization mode
authorization:
  rbac: { enabled: true }
  admin_list: { enabled: false }
Defensive patterns

Strategy: validation

Validate before calling

// config sanity before startup: exactly one authorization mode, consistent flags
def validate_authz(cfg):
    rbac = cfg['authorization']['rbac']['enabled']
    admin = cfg['authorization']['admin_list']['enabled']
    assert not (rbac and not rbac_supported()), "RBAC enabled but build/config path unavailable"
    assert rbac or admin or cfg['authorization'].get('allow_anonymous'), "no authorizer mode configured"

Prevention

When it happens

Trigger: `authorization.rbac.enabled=true` while configureAuthorizer returned from a different branch (e.g. rbac.New was skipped due to an internal condition, or an earlier wrapped failure left appState.RBAC nil before this guard ran). The comment in the source says this "in general shall not happen" — it catches partially failed initialization.

Common situations: Patched/custom builds where the RBAC assignment path was altered; config where both rbac and admin_list flags interact unexpectedly; race or partial failure during startupRoutine before the earlier rbac.New error could abort startup.

Related errors


AI-assisted analysis of weaviate/weaviate@75aa4b6d11 (2026-09-04). Data as JSON: /api/errors/b783f0d972e9ebef. Report an issue: GitHub.