-
Type:
Bug
-
Resolution: Unresolved
-
Priority:
Low
-
None
-
Affects Version/s: 9.2.0, 9.2.1, 9.2.3, 9.2.4, 9.2.5, 9.2.6, 9.2.7, 9.2.8, 9.2.9, 9.2.10
-
Component/s: Content - Attachments
-
None
-
2
-
Severity 3 - Minor
Issue Summary
During the execution of the Fast Trash Removal (Automated Data Eviction) job, Confluence encounters an error when attempting to permanently delete trashed attachments whose actual files are missing from disk. The job fails with the following exception:
java.lang.IllegalArgumentException: Can't generate cache key for attachment with no content
This occurs because the attachment file is deleted from the filesystem before its corresponding database record and cache invalidation are safely handled. As a result, Confluence rolls back the current batch transaction and retries deletion item-by-item. During the retry phase, additional errors are logged indicating missing attachment paths on disk, such as:
Could not find attachment folder to remove at [/var/atlassian/application-data/confluence/shared/attachments/v4/...]
This behavior suggests a flaw in the attachment deletion sequence within ReadThroughCachingAttachmentManager.removeAttachmentWithoutNotifications(), where Confluence attempts to generate a cache key for a content object that no longer exists. Consequently, trashed attachments remain undeleted in the database, and the Fast Trash Removal job does not fully complete as expected.
Steps to Reproduce
- Created a page with an attachment.
- Retention Rule for space set as:
- Attachments: Keep all
- Page versions: 1 version
- Trash: 1 day
- Deleted the page to Trash
- Execute the following SQL to update the dates of items in the trash so that they come within the retention policy.
Postgre
UPDATE CONTENTPROPERTIES SET LONGVAL = EXTRACT(EPOCH FROM (CURRENT_DATE - INTERVAL '2 days')::timestamp) * 1000 WHERE PROPERTYNAME = 'trash-date';
- Flushed the cache from Cache Management
- Run the Trash Removal (Soft).
- Similar logs will be printed:
2025-11-21 10:34:24,922 ERROR [Caesium-1-4] [impl.retention.fast.FastTrashRemovalManager] lambda$removeTrashContents$5 error during fast trash removal, skipping to next removal batch: -- url: /confluence/setup/finishsetup.action | userName: anonymous | action: finishsetup | referer: https://linux-114235.prod.atl-cd.net/confluence/setup/setupadministrator-start.action | traceId: e3e8f384c9400ee1 java.lang.IllegalArgumentException: Can't generate cache key for attachment with no content: Attachment: Sceanrio 1.txt v.1 (393333) admin at com.google.common.base.Preconditions.checkArgument(Preconditions.java:220) at com.atlassian.confluence.impl.pages.attachments.ReadThroughAttachmentDownloadPathCache.toKey(ReadThroughAttachmentDownloadPathCache.java:41) at com.atlassian.confluence.impl.pages.attachments.ReadThroughCachingAttachmentManager.invalidateCache(ReadThroughCachingAttachmentManager.java:204) at com.atlassian.confluence.impl.pages.attachments.ReadThroughCachingAttachmentManager.removeAttachmentWithoutNotifications(ReadThroughCachingAttachmentManager.java:131) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:355) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:165) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at com.atlassian.spring.interceptors.SpringProfilingInterceptor.invoke(SpringProfilingInterceptor.java:16) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at com.atlassian.confluence.util.profiling.ConfluenceMonitoringMethodInterceptor.invoke(ConfluenceMonitoringMethodInterceptor.java:36) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223) at jdk.proxy4/jdk.proxy4.$Proxy425.removeAttachmentWithoutNotifications(Unknown Source) at com.atlassian.confluence.pages.DefaultTrashManager.deleteContentEntity(DefaultTrashManager.java:307) at com.atlassian.confluence.pages.DefaultTrashManager.lambda$purge$1(DefaultTrashManager.java:254) at java.base/java.lang.Iterable.forEach(Iterable.java:75) at com.atlassian.confluence.pages.DefaultTrashManager.purge(DefaultTrashManager.java:254) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:355) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:165) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at com.atlassian.spring.interceptors.SpringProfilingInterceptor.invoke(SpringProfilingInterceptor.java:16) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at com.atlassian.confluence.util.profiling.ConfluenceMonitoringMethodInterceptor.invoke(ConfluenceMonitoringMethodInterceptor.java:36) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223) at jdk.proxy4/jdk.proxy4.$Proxy464.purge(Unknown Source) at com.atlassian.confluence.impl.retention.manager.AbstractTrashRemovalManager.deleteForRule(AbstractTrashRemovalManager.java:74) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.lambda$removeTrashContents$4(FastTrashRemovalManager.java:210) at com.atlassian.confluence.impl.retention.analytics.TrashRemovalStatisticThreadLocal.withStatistic(TrashRemovalStatisticThreadLocal.java:23) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.lambda$removeTrashContents$5(FastTrashRemovalManager.java:210) at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.removeTrashContents(FastTrashRemovalManager.java:196) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.removeTrashContentsWithRetry(FastTrashRemovalManager.java:168) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.removeTrashesOfOnePolicy(FastTrashRemovalManager.java:143) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.removeTrashesOfOneSpace(FastTrashRemovalManager.java:130) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.lambda$internalSoftRemove$1(FastTrashRemovalManager.java:116) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.internalSoftRemove(FastTrashRemovalManager.java:116) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.lambda$softRemove$0(FastTrashRemovalManager.java:90) at com.atlassian.confluence.impl.cluster.lock.ClusterLockExecutionService.doWithLock(ClusterLockExecutionService.java:29) at com.atlassian.confluence.impl.retention.fast.FastTrashRemovalManager.softRemove(FastTrashRemovalManager.java:89) at com.atlassian.confluence.impl.retention.schedule.TrashSoftRemovalScheduledJob.runJob(TrashSoftRemovalScheduledJob.java:49) at com.atlassian.confluence.impl.schedule.caesium.JobRunnerWrapper.doRunJob(JobRunnerWrapper.java:121) at com.atlassian.confluence.impl.schedule.caesium.JobRunnerWrapper.runJob(JobRunnerWrapper.java:83) at com.atlassian.scheduler.caesium.impl.CaesiumSchedulerService$JobRunnerWithStats.runJob(CaesiumSchedulerService.java:743) at com.atlassian.scheduler.core.JobLauncher.runJob(JobLauncher.java:134) at com.atlassian.scheduler.core.JobLauncher.launchAndBuildResponse(JobLauncher.java:106) at com.atlassian.scheduler.core.JobLauncher.launch(JobLauncher.java:90) at com.atlassian.scheduler.caesium.impl.CaesiumSchedulerService.launchJob(CaesiumSchedulerService.java:545) at com.atlassian.scheduler.caesium.impl.CaesiumSchedulerService.executeLocalJobWithRetryOnFailure(CaesiumSchedulerService.java:500) at com.atlassian.scheduler.caesium.impl.CaesiumSchedulerService.executeQueuedJob(CaesiumSchedulerService.java:440) at com.atlassian.scheduler.caesium.impl.SchedulerQueueWorker.executeJob(SchedulerQueueWorker.java:66) at com.atlassian.scheduler.caesium.impl.SchedulerQueueWorker.executeNextJob(SchedulerQueueWorker.java:60) at com.atlassian.scheduler.caesium.impl.SchedulerQueueWorker.run(SchedulerQueueWorker.java:35) at java.base/java.lang.Thread.run(Thread.java:1583) 2025-11-21 10:34:24,923 WARN [Caesium-1-4] [confluence.impl.hibernate.ConfluenceHibernateTransactionManager] doRollback Performing rollback. Transactions:\n ->[TrashRemovalService]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT (Session #1747429507)\n [null]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,readOnly (Session #626968819) -- url: /confluence/setup/finishsetup.action | userName: anonymous | action: finishsetup | referer: https://linux-114235.prod.atl-cd.net/confluence/setup/setupadministrator-start.action | traceId: e3e8f384c9400ee1 2025-11-21 10:34:24,927 DEBUG [Caesium-1-4] [impl.retention.fast.FastTrashRemovalManager] debug Fast trash removal - Trash deletion in batch failed, retry deletion one by one. | traceId: e3e8f384c9400ee1 2025-11-21 10:34:24,975 ERROR [Caesium-1-4] [pages.attachments.filesystem.ContentDirectoryStructureAttachmentDataFileSystemV004] deleteAllAttachmentVersions Could not find attachment folder to remove at [/var/atlassian/application-data/confluence/shared/attachments/v4/123/0/393333]. -- url: /confluence/setup/finishsetup.action | userName: anonymous | action: finishsetup | referer: https://linux-114235.prod.atl-cd.net/confluence/setup/setupadministrator-start.action | traceId: e3e8f384c9400ee1
Expected Results
When the Fast Trash Removal job runs:
- Confluence should successfully identify and permanently remove all trashed content, including pages, comments, and attachments.
- For trashed attachments:
- The system should first validate that the attachment’s content record and binary reference exist.
- It should then remove the database record, clear associated cache entries, and finally delete the file from disk — in that order.
- If the attachment file is already missing from disk, Confluence should:
- Gracefully skip deletion of the missing file without throwing an exception.
- Log a clear warning indicating that the file was not found but was cleaned up from the database.
As a result, the trash cleanup completes successfully without transaction rollbacks, cache key errors, or partial deletions.
Actual Results
- The job fails to complete the batch deletion successfully.
- Some trashed attachments remain in the database despite their files being deleted.
- Repeated "cache key" and "missing path" errors appear in the logs each time the eviction job runs.
Workaround
Currently, there is no known workaround for this behaviour. A workaround will be added here when available.
The error can be ignored as attachments get deleted, but logging is not correct.