spring-projects/spring-security · error · NotFoundException

Object identity not found for ACL: <objectIdentity>

Error message

Object identity not found for ACL: <objectIdentity>

What it means

updateAcl persists ACE changes by deleting and recreating the acl_entry rows for the ACL, which requires the acl_object_identity primary key for the ACL's ObjectIdentity. If no persisted ACL row matches that identity, NotFoundException("Object identity not found for ACL") is thrown — you cannot update an ACL that was never created via createAcl.

Source

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

		catch (DataAccessException notFound) {
			return null;
		}
	}

	/**
	 * This implementation will simply delete all ACEs in the database and recreate them
	 * on each invocation of this method. A more comprehensive implementation might use
	 * dirty state checking, or more likely use ORM capabilities for create, update and
	 * delete operations of {@link MutableAcl}.
	 */
	@Override
	public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
		Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");

		// Delete this ACL's ACEs in the acl_entry table
		Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity());
		if (oidPrimaryKey == null) {
			throw new NotFoundException("Object identity not found for ACL: " + acl.getObjectIdentity());
		}
		deleteEntries(oidPrimaryKey);

		// Create this ACL's ACEs in the acl_entry table
		createEntries(acl);

		// Change the mutable columns in acl_object_identity
		updateObjectIdentity(acl);

		// Clear the cache, including children
		clearCacheIncludingChildren(acl.getObjectIdentity());

		// Retrieve the ACL via superclass (ensures cache registration, proper retrieval
		// etc)
		return (MutableAcl) super.readAclById(acl.getObjectIdentity());
	}

	private void clearCacheIncludingChildren(ObjectIdentity objectIdentity) {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Call createAcl(objectIdentity) first, then mutate and updateAcl the returned MutableAcl.
  2. Obtain the MutableAcl from readAclById/readAclsById instead of constructing AclImpl instances manually.
  3. Catch NotFoundException and fall back to createAcl for identities that may be new.
  4. Ensure no concurrent deleteAcl races with updateAcl (wrap in a transaction).

Example fix

// before
MutableAcl acl = new AclImpl(oid, 1L, aclAuthorizationStrategy, new ConsoleAuditLogger());
acl.insertAce(0, permission, sid, true);
mutableAclService.updateAcl(acl);
// after
MutableAcl acl = (MutableAcl) aclService.readAclById(oid);
acl.insertAce(acl.getEntries().size(), permission, sid, true);
mutableAclService.updateAcl(acl);
Defensive patterns

Strategy: try-catch

Validate before calling

if (((JdbcMutableAclService) aclService).retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()) == null) {
    mutableAclService.createAcl(acl.getObjectIdentity());
}

Type guard

null

Try / catch

try {
    mutableAclService.updateAcl(acl);
} catch (NotFoundException e) {
    MutableAcl created = mutableAclService.createAcl(acl.getObjectIdentity());
    // re-apply changes to created
}

Prevention

When it happens

Trigger: Building a MutableAclImpl in memory (e.g. new AclImpl(oid, ...)) or mutating an ACL obtained elsewhere and calling updateAcl without ever having called createAcl for that object identity; calling updateAcl after the ACL row was deleted concurrently.

Common situations: Constructing ACL objects programmatically in tests or batch jobs instead of reading them from the service; applying ACE changes to a brand-new entity before ACL creation; a concurrent deleteAcl removing the row between read and update.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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