spring-projects/spring-security · error · IllegalStateException

authorizationManagerFactory must be an instance of DefaultAu

Error message

authorizationManagerFactory must be an instance of DefaultAuthorizationManagerFactory

What it means

SecurityExpressionRoot keeps an AuthorizationManagerFactory; deprecated setters (setTrustResolver, setRoleHierarchy, setDefaultRolePrefix) still work by mutating the field only if it is a DefaultAuthorizationManagerFactory. If a custom AuthorizationManagerFactory was installed via setAuthorizationManagerFactory, calling these legacy setters throws IllegalStateException because the legacy mutation cannot be applied.

Source

Thrown at core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java:288

	 */
	public void setAuthorizationManagerFactory(AuthorizationManagerFactory<T> authorizationManagerFactory) {
		Assert.notNull(authorizationManagerFactory, "authorizationManagerFactory cannot be null");
		this.authorizationManagerFactory = authorizationManagerFactory;
	}

	/**
	 * Allows accessing the {@link DefaultAuthorizationManagerFactory} for getting and
	 * setting defaults. This method will be removed in Spring Security 8.
	 * @return the {@link DefaultAuthorizationManagerFactory}
	 * @throws IllegalStateException if a different {@link AuthorizationManagerFactory}
	 * was already set
	 * @deprecated Use
	 * {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
	 */
	@Deprecated(since = "7.0", forRemoval = true)
	private DefaultAuthorizationManagerFactory<T> getDefaultAuthorizationManagerFactory() {
		if (!(this.authorizationManagerFactory instanceof DefaultAuthorizationManagerFactory<T> defaultAuthorizationManagerFactory)) {
			throw new IllegalStateException(
					"authorizationManagerFactory must be an instance of DefaultAuthorizationManagerFactory");
		}

		return defaultAuthorizationManagerFactory;
	}

	@Override
	public boolean hasPermission(Object target, Object permission) {
		return this.permissionEvaluator.hasPermission(getAuthentication(), target, permission);
	}

	@Override
	public boolean hasPermission(Object targetId, String targetType, Object permission) {
		return this.permissionEvaluator.hasPermission(getAuthentication(), (Serializable) targetId, targetType,
				permission);
	}

	public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Stop using the deprecated setters; configure role hierarchy via the AuthorizationManagerFactory instead
  2. Set the role hierarchy/prefix before any deprecated setter is called, or use DefaultAuthorizationManagerFactory explicitly
  3. Replace setRoleHierarchy(...) with RoleHierarchyAuthorityMappingStrategy wiring on the authorization manager
  4. Update custom code to use setAuthorizationManagerFactory(new DefaultAuthorizationManagerFactory<>()) configured with the desired prefix

Example fix

// before
handler.setRoleHierarchy(roleHierarchy);
handler.setAuthorizationManagerFactory(customFactory);
// after
DefaultAuthorizationManagerFactory<Object> factory = new DefaultAuthorizationManagerFactory<>();
factory.setRoleHierarchy(roleHierarchy);
handler.setAuthorizationManagerFactory(factory);
Defensive patterns

Strategy: validation

Validate before calling

if (!(root.getAuthorizationManagerFactory() instanceof DefaultAuthorizationManagerFactory)) {
  throw new IllegalStateException("Use setAuthorizationManagerFactory instead of deprecated setters");
}

Type guard

if (factory instanceof DefaultAuthorizationManagerFactory<?> d) { d.setDefaultRolePrefix(prefix); }

Try / catch

try { root.setDefaultRolePrefix("ROLE_"); }
catch (IllegalStateException e) { configureViaFactory(); }

Prevention

When it happens

Trigger: Calling setDefaultRolePrefix, setTrustResolver, or setRoleHierarchy on a SecurityExpressionRoot (or handler configured with one) after replacing the authorizationManagerFactory with a non-default AuthorizationManagerFactory implementation.

Common situations: Migrating from Spring Security 5.x/6.x role-prefix/hierarchy setters to the 7.0 AuthorizationManagerFactory API; mixing deprecated configuration with new custom factory beans.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/6e4b0c6b839b4541. Report an issue: GitHub.