spring-projects/spring-security · error · ChildrenExistException

Cannot delete ' ' (has children)

Error message

Cannot delete '<objectIdentity>' (has <N> children)

What it means

JdbcMutableAclService.deleteAcl refuses to delete an ACL that still has child ACLs (children whose acl_object_identity.parent equals the target). When foreignKeysInDatabase is false (no DB-level FK cascade constraints), the service manually checks findChildren and throws ChildrenExistException if any exist. This prevents orphaning child ACLs that inherit from the deleted parent.

Solutions

  1. Delete child ACLs first (recursively via findChildren), then delete the parent.
  2. Call deleteAcl with deleteChildren=true to cascade the deletion.
  3. Add proper foreign key constraints to acl_object_identity (parent FK with ON DELETE CASCADE) and set foreignKeysInDatabase=true so the DB handles it.
  4. Catch org.springframework.security.acls.model.ChildrenExistException and surface a 'remove children first' condition to the caller.

Example fix

// before
mutableAclService.deleteAcl(oid, false);
// after
mutableAclService.deleteAcl(oid, true); // cascade-delete children ACLs
Defensive patterns

Strategy: try-catch

Validate before calling

List<ObjectIdentity> children = ((JdbcMutableAclService) aclService).findChildren(oid);
if (children != null && !children.isEmpty() && !deleteChildren) { /* resolve first */ }

Type guard

null

Try / catch

try {
    mutableAclService.deleteAcl(oid, false);
} catch (ChildrenExistException e) {
    // delete children recursively first, then retry
}

Prevention

When it happens

Trigger: Calling deleteAcl(objectIdentity, deleteChildren=false) on an ACL that is the parent of other ACLs while the database schema lacks the foreign keys (foreignKeysInDatabase=false), e.g. the default sample schema without FK definitions.

Common situations: Deleting a parent domain object (e.g. a folder) whose children (files) have their own ACLs; running against the standard ACL schema where acl_object_identity has no FK constraints; cascading entity deletes in application code that skip ACL child cleanup.

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/60fb5f5f19feb2a8. Report an issue: GitHub.

Appendix: source

Thrown at acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java:292

	@Override
	public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException {
		Assert.notNull(objectIdentity, "Object Identity required");
		Assert.notNull(objectIdentity.getIdentifier(), "Object Identity doesn't provide an identifier");
		if (deleteChildren) {
			List<ObjectIdentity> children = findChildren(objectIdentity);
			if (children != null) {
				for (ObjectIdentity child : children) {
					deleteAcl(child, true);
				}
			}
		}
		else {
			if (!this.foreignKeysInDatabase) {
				// We need to perform a manual verification for what a FK would normally
				// do. We generally don't do this, in the interests of deadlock management
				List<ObjectIdentity> children = findChildren(objectIdentity);
				if (children != null) {
					throw new ChildrenExistException(
							"Cannot delete '" + objectIdentity + "' (has " + children.size() + " children)");
				}
			}
		}

		Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(objectIdentity);
		if (oidPrimaryKey == null) {
			throw new NotFoundException("Object identity not found: " + objectIdentity);
		}

		// Delete this ACL's ACEs in the acl_entry table
		deleteEntries(oidPrimaryKey);

		// Delete this ACL's acl_object_identity row
		deleteObjectIdentity(oidPrimaryKey);

		// Clear the cache
		this.aclCache.evictFromCache(objectIdentity);

View on GitHub (pinned to 96852e8860)