{"record":{"id":"9da87badc4315adc","repo":"spring-projects/spring-security","slug":"object-identity-not-found-for-acl-objectidentity","errorCode":null,"errorMessage":"Object identity not found for ACL: <objectIdentity>","messagePattern":"Object identity not found for ACL: <objectIdentity>","errorType":"exception","errorClass":"NotFoundException","httpStatus":null,"severity":"error","filePath":"acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java","lineNumber":366,"sourceCode":"\t\tcatch (DataAccessException notFound) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * This implementation will simply delete all ACEs in the database and recreate them\n\t * on each invocation of this method. A more comprehensive implementation might use\n\t * dirty state checking, or more likely use ORM capabilities for create, update and\n\t * delete operations of {@link MutableAcl}.\n\t */\n\t@Override\n\tpublic MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {\n\t\tAssert.notNull(acl.getId(), \"Object Identity doesn't provide an identifier\");\n\n\t\t// Delete this ACL's ACEs in the acl_entry table\n\t\tLong oidPrimaryKey = retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity());\n\t\tif (oidPrimaryKey == null) {\n\t\t\tthrow new NotFoundException(\"Object identity not found for ACL: \" + acl.getObjectIdentity());\n\t\t}\n\t\tdeleteEntries(oidPrimaryKey);\n\n\t\t// Create this ACL's ACEs in the acl_entry table\n\t\tcreateEntries(acl);\n\n\t\t// Change the mutable columns in acl_object_identity\n\t\tupdateObjectIdentity(acl);\n\n\t\t// Clear the cache, including children\n\t\tclearCacheIncludingChildren(acl.getObjectIdentity());\n\n\t\t// Retrieve the ACL via superclass (ensures cache registration, proper retrieval\n\t\t// etc)\n\t\treturn (MutableAcl) super.readAclById(acl.getObjectIdentity());\n\t}\n\n\tprivate void clearCacheIncludingChildren(ObjectIdentity objectIdentity) {","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java#L348-L384","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call createAcl(objectIdentity) first, then mutate and updateAcl the returned MutableAcl.","Obtain the MutableAcl from readAclById/readAclsById instead of constructing AclImpl instances manually.","Catch NotFoundException and fall back to createAcl for identities that may be new.","Ensure no concurrent deleteAcl races with updateAcl (wrap in a transaction)."],"exampleFix":"// before\nMutableAcl acl = new AclImpl(oid, 1L, aclAuthorizationStrategy, new ConsoleAuditLogger());\nacl.insertAce(0, permission, sid, true);\nmutableAclService.updateAcl(acl);\n// after\nMutableAcl acl = (MutableAcl) aclService.readAclById(oid);\nacl.insertAce(acl.getEntries().size(), permission, sid, true);\nmutableAclService.updateAcl(acl);","handlingStrategy":"try-catch","validationCode":"if (((JdbcMutableAclService) aclService).retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()) == null) {\n    mutableAclService.createAcl(acl.getObjectIdentity());\n}","typeGuard":"null","tryCatchPattern":"try {\n    mutableAclService.updateAcl(acl);\n} catch (NotFoundException e) {\n    MutableAcl created = mutableAclService.createAcl(acl.getObjectIdentity());\n    // re-apply changes to created\n}","preventionTips":["Never construct AclImpl instances manually for persistence; read them from the service","Create the ACL before mutating ACEs for new entities","Wrap read-modify-write in a transaction to avoid concurrent deletes"],"tags":["spring-security","acl","not-found","update"],"backgroundTag":"entity-not-found","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}