Skip to content

Realm import with --import-realm fails with ModelValidationException when Admin Permissions is enabled #47901

@dpiva97

Description

@dpiva97

Before reporting an issue

  • I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

Area

import-export

Describe the bug

Starting from Keycloak 26.6.0, importing a previously exported realm using the --import-realm flag fails with a ModelValidationException when the realm has Admin Permissions enabled.
The error occurs in AdminPermissionsSchema.getOrCreateResource() (in server-spi-private/src/main/java/org/keycloak/authorization/fgap/AdminPermissionsSchema.java).

Version

26.6.0

Regression

  • The issue is a regression

Expected behavior

Importing a realm (previously exported from the same version) with --import-realm should complete successfully.

Actual behavior

The server fails to start and the import is aborted with the following error:

JAVA_OPTS already set in environment; overriding default settings
Listening for transport dt_socket at address: 9787
Updating the configuration and installing your custom providers, if any. Please wait.
2026-04-09 11:11:56,187 INFO  [io.quarkus.deployment.QuarkusAugmentor] (main) Quarkus augmentation completed in 6064ms
Listening for transport dt_socket at address: 9787
Running the server in development mode. DO NOT use this configuration in production.
2026-04-09 11:11:59,883 INFO  [org.infinispan.CONTAINER] (main) ISPN000974: Virtual threads support: enabled
2026-04-09 11:12:00,620 INFO  [org.hibernate.orm.jdbc.batch] (JPA Startup Thread) HHH100501: Automatic JDBC statement batching enabled (maximum batch size 32)
2026-04-09 11:12:01,582 INFO  [org.keycloak.quarkus.runtime.storage.database.liquibase.QuarkusJpaUpdaterProvider] (main) Initializing database schema. Using changelog META-INF/jpa-changelog-master.xml
2026-04-09 11:12:06,850 INFO  [org.infinispan.CONTAINER] (main) ISPN000556: Starting user marshaller 'org.infinispan.commons.marshall.ImmutableProtoStreamMarshaller'
2026-04-09 11:12:07,164 INFO  [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (main) Node name: node_622802, Site name: null
2026-04-09 11:12:07,346 INFO  [org.keycloak.models.workflow.WorkflowsEventListenerFactory] (main) Workflow runner task scheduled: next execution at 23:12:07, then every PT12H
2026-04-09 11:12:07,396 INFO  [org.keycloak.exportimport.dir.DirImportProvider] (main) Importing from directory /opt/keycloak/bin/../data/import
2026-04-09 11:12:07,577 INFO  [org.keycloak.services] (main) KC-SERVICES0050: Initializing master realm
2026-04-09 11:12:08,981 INFO  [org.keycloak.exportimport.singlefile.SingleFileImportProvider] (main) Full importing from file /opt/keycloak/bin/../data/import/realm.json
2026-04-09 11:12:10,468 INFO  [com.arjuna.ats.jbossatx] (main) ARJUNA032014: Stopping transaction recovery manager
2026-04-09 11:12:10,487 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to start server in (development) mode
2026-04-09 11:12:10,487 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) Error details:: org.keycloak.models.ModelValidationException: Resource [Users] does not exist for type [Users]
	at org.keycloak.authorization.fgap.AdminPermissionsSchema.lambda$getOrCreateResource$3(AdminPermissionsSchema.java:149)
	at java.base/java.util.Optional.orElseThrow(Optional.java:403)
	at org.keycloak.authorization.fgap.AdminPermissionsSchema.getOrCreateResource(AdminPermissionsSchema.java:149)
	at org.keycloak.models.utils.RepresentationToModel.lambda$updateResources$12(RepresentationToModel.java:1461)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1715)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
	at org.keycloak.models.utils.RepresentationToModel.updateResources(RepresentationToModel.java:1468)
	at org.keycloak.models.utils.RepresentationToModel.toModel(RepresentationToModel.java:1311)
	at org.keycloak.authorization.AuthorizationProvider$3.create(AuthorizationProvider.java:349)
	at org.keycloak.models.utils.RepresentationToModel.importPolicies(RepresentationToModel.java:1237)
	at org.keycloak.models.utils.RepresentationToModel.toModel(RepresentationToModel.java:1184)
	at org.keycloak.models.utils.RepresentationToModel.importAuthorizationSettings(RepresentationToModel.java:1131)
	at org.keycloak.storage.datastore.DefaultExportImportManager.lambda$importRealmAuthorizationSettings$12(DefaultExportImportManager.java:1622)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at org.keycloak.storage.datastore.DefaultExportImportManager.importRealmAuthorizationSettings(DefaultExportImportManager.java:1620)
	at org.keycloak.storage.datastore.DefaultExportImportManager.importRealm(DefaultExportImportManager.java:493)
	at org.keycloak.models.utils.RepresentationToModel.importRealm(RepresentationToModel.java:150)
	at org.keycloak.services.managers.RealmManager.importRealm(RealmManager.java:657)
	at org.keycloak.exportimport.util.ImportUtils.importRealm(ImportUtils.java:128)
	at org.keycloak.exportimport.util.ImportUtils.importRealms(ImportUtils.java:66)
	at org.keycloak.exportimport.singlefile.SingleFileImportProvider$1.runExportImportTask(SingleFileImportProvider.java:66)
	at org.keycloak.exportimport.util.ExportImportSessionTask.lambda$run$1(ExportImportSessionTask.java:58)
	at org.keycloak.exportimport.util.ExportImportSessionTask.run(ExportImportSessionTask.java:66)
	at org.keycloak.exportimport.util.ExportImportSessionTask.runTask(ExportImportSessionTask.java:49)
	at org.keycloak.exportimport.util.ExportImportSessionTask.runTask(ExportImportSessionTask.java:42)
	at org.keycloak.exportimport.singlefile.SingleFileImportProvider.importModel(SingleFileImportProvider.java:69)
	at org.keycloak.exportimport.ExportImportManager.lambda$runImport$1(ExportImportManager.java:105)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)

How to Reproduce?

  • Start a Keycloak 26.6.0 instance.
  • Create a realm with Admin Permissions enabled.
  • Create a user resource permission with a client based policy (eg. account-console).
  • Export the realm to a JSON file via the export command.
  • Start a new Keycloak 26.6.0 instance with the --import-realm flag, placing the exported JSON file in the data/import directory.
  • Observe the server failing to start with the error ModelValidationException: Resource [Users] does not exist for type [Users].

Anything else?

I believe the root cause is that AdminPermissionsSchema.getOrCreateResource() unconditionally calls .orElseThrow() when resolveUser() (or the other resolve methods) returns an empty .

26.5.7

String name;
switch (resourceType) {
        case CLIENTS_RESOURCE_TYPE -> name = resolveClient(session, id).map(ClientModel::getId).orElse(resourceType);
        case GROUPS_RESOURCE_TYPE -> name = resolveGroup(session, id).map(GroupModel::getId).orElse(resourceType);
        case ROLES_RESOURCE_TYPE -> name = resolveRole(session, id).map(RoleModel::getId).orElse(resourceType);
        case USERS_RESOURCE_TYPE -> name = resolveUser(session, id).map(UserModel::getId).orElse(resourceType);
        default -> throw new IllegalStateException("Resource type [" + resourceType + "] not found.");
}
resource = resourceStore.findByName(resourceServer, name);

26.6.0

String name;
switch (resourceType) {
        case CLIENTS_RESOURCE_TYPE -> name = resolveClient(session, id).map(ClientModel::getId).orElseThrow(() -> new ModelValidationException("Resource [" + id + "] does not exist for type [" + resourceType + "]"));
        case GROUPS_RESOURCE_TYPE -> name = resolveGroup(session, id).map(GroupModel::getId).orElseThrow(() -> new ModelValidationException("Resource [" + id + "] does not exist for type [" + resourceType + "]"));
        case ROLES_RESOURCE_TYPE -> name = resolveRole(session, id).map(RoleModel::getId).orElseThrow(() -> new ModelValidationException("Resource [" + id + "] does not exist for type [" + resourceType + "]"));
        case USERS_RESOURCE_TYPE -> name = resolveUser(session, id).map(UserModel::getId).orElseThrow(() -> new ModelValidationException("Resource [" + id + "] does not exist for type [" + resourceType + "]"));
        default -> throw new IllegalStateException("Resource type [" + resourceType + "] not found.");
}
resource = resourceStore.findByName(resourceServer, name);

Metadata

Metadata

Assignees

Type

No fields configured for bug.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions