-
Bug
-
Resolution: Unresolved
-
Low
-
None
-
8.7.1, 9.2.8, 10.0.3
-
4
-
Severity 2 - Major
-
41
-
-
CtB - Improve Existing
Issue Summary
In certain situations (for example flawed page-tree moves or page-reordering attempts), Confluence content-hierarchy can form a cyclic loop where:
- content A’s parent gets pointed to content B, while
- content B’s parent points back to content A
While such loops are benign and are dealt with in a safe fashion on the Confluence UI (say during the rendering of the page-tree) via informative errors on the screen, if the content involved in the loop has inline tasks on either page (which may be referenced in a task report), then Confluence will run out of memory while executing InlineTaskIndexQueueFlusherJob/scheduledjob.desc.flushTaskIndexQueue.
On the Confluence web interface, loading either page (with the Configure sidebar option set to Page-tree) will show the following error on the left-side page-tree:
Error rendering macro 'pagetree'
Cyclic loop is detected in page tree structure. Please report to admin.
Corresponding to the errors on the Confluence UI, the following patterns will be seen in the atlassian-confluence.log:
2025-09-12 11:28:03,240 WARN [http-nio-8090-exec-8 url: /spaces/NEW/pages/393236/pageB, /pages/viewpage.action; user: admin] [xhtml.view.macro.ViewMacroMarshaller] handleMacroExecutionException Exception executing macro: pagetree, with message: Cyclic loop is detected in page tree structure. Please report to admin. 2025-09-12 11:28:09,834 WARN [http-nio-8090-exec-2 url: /spaces/NEW/pages/393229/pageA, /pages/viewpage.action; user: admin] [xhtml.view.macro.ViewMacroMarshaller] handleMacroExecutionException Exception executing macro: pagetree, with message: Cyclic loop is detected in page tree structure. Please report to admin.
In the Confluence database, for such situations, the content table will have entries for the corresponding pages like this example (contentid and parentid highlighted to show the loop, only selected columns shown for brevity):
| contentid | contenttype | lowertitle | content_status | spaceid | parentid |
|---|---|---|---|---|---|
| 393229 | PAGE | pagea | current | 622593 | 393236 |
| 393236 | PAGE | pageb | current | 622593 | 393229 |
Crucially, if inline tasks are present on either page, and if a task report is configured to reference that data, then Confluence will run out of memory:
- either while Confluence reindexes the task_report_index (during a manually triggered reindex operation, or during index-rebuild (as the final option exercised during index-recovery) during Confluence startup)
- or when an update of referenced tasks is picked up by the regularly scheduled task report index flush job (Administration → Scheduled Jobs → scheduledjob.desc.flushTaskIndexQueue)
Steps to Reproduce
- Create 2 Confluence pages, page A and page B, where page B is the child of page A
- On both pages, add an inline task
- Add a task report macro (on any page), and ensure that the macro filters pick up the tasks on the corresponding pages
- Stop Confluence, and manually modify the content table in such a way that page A’s parent is child page B, and child page B’s parent is parent page A, like this:
update content set parentid=393236 where contentid=393229; update content set parentid=393229 where contentid=393236;
- Trigger the memory error by any one of the following ways:
- Force a task index rebuild at startup:
- remove the directory <confluence-local-home>/index/task_report_index and file <confluence-local-home>/journal/task_report_index
- ensure that <confluence-shared-home>/index-snapshots has no usable snapshot zip, and the Confluence node that this is being used for this attempt has -Dconfluence.cluster.index.recovery.num.attempts=0 in its setenv to prevent it from getting a usable index from another node (if the instance is running as a multi-node cluster)
- start Confluence
- the conditions for task index recovery will be met, and since no usable task index snapshot zip is available at <confluence-shared-home>/index-snapshots, plus the seeking of assistance from other nodes of the cluster being blocked via -Dconfluence.cluster.index.recovery.num.attempts=0, a full rebuild of the task index will then be triggered
- Wait for the background job scheduledjob.desc.flushTaskIndexQueue to execute on the cyclic looped content (the job runs every 5 seconds by default).
- Navigate to Administration → Content indexing → either click Site reindex (to reindex all content) or click Space reindex (to reindex just the space that hosts the cyclic-looped pages (with tasks on them, as well as a task report that references those tasks)).
- Force a task index rebuild at startup:
Expected Results
Confluence should handle cyclic loops gracefully and abandon the task report index (re)build effort without crashing if a loop is detected.
Actual Results
Confluence runs out of memory leaving behind java.lang.OutOfMemoryError: Java heap space related stack traces (and a heap dump, if the setting is enabled) pointing to the failure in (re)building the task report index because of the cyclic loop while executing com.atlassian.confluence.plugins.tasklist.report.searchindex.InlineTaskSearchDocumentFactory’s getPageAncestors() method.
The atlassian-confluence.log will show the following log-patterns for the memory leak:
2025-09-12 11:04:04,125 WARN [pool-15-thread-1] [confluence.impl.hibernate.ConfluenceHibernateTransactionManager] doRollback Performing rollback. Transactions:\n ->[PluginReadWriteTx]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT (Session #957460823) 2025-09-12 11:04:04,161 ERROR [Caesium-1-1] [searchindex.indexmanagement.scheduling.InlineTaskIndexQueueFlusherJob] runJob Unable to run task report index flush job java.lang.IllegalStateException: Something went wrong with indexing: java.lang.OutOfMemoryError: Java heap space at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer.addAllInlineTasksToSearchIndex(FullReIndexer.java:158) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer.reindexAllTasks(FullReIndexer.java:81) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.indexqueue.IndexQueueProcessorImpl.processJournalEntries(IndexQueueProcessorImpl.java:134) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.indexqueue.IndexQueueProcessorImpl.flushQueue(IndexQueueProcessorImpl.java:278) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.scheduling.InlineTaskIndexQueueFlusherJob.runJob(InlineTaskIndexQueueFlusherJob.java:33) 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) Caused by: java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Java heap space at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer.indexNextBatchOfInlineTasksInSeparateTransaction(FullReIndexer.java:105) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer.addAllInlineTasksToSearchIndex(FullReIndexer.java:154) ... 17 more Caused by: java.lang.OutOfMemoryError: Java heap space at java.base/java.util.Arrays.copyOf(Arrays.java:3482) at java.base/java.util.ArrayList.grow(ArrayList.java:237) at java.base/java.util.ArrayList.grow(ArrayList.java:244) at java.base/java.util.ArrayList.add(ArrayList.java:483) at java.base/java.util.ArrayList.add(ArrayList.java:496) at com.atlassian.confluence.plugins.tasklist.report.searchindex.InlineTaskSearchDocumentFactory.getPageAncestors(InlineTaskSearchDocumentFactory.java:154) at com.atlassian.confluence.plugins.tasklist.report.searchindex.InlineTaskSearchDocumentFactory.addAncestors(InlineTaskSearchDocumentFactory.java:132) at com.atlassian.confluence.plugins.tasklist.report.searchindex.InlineTaskSearchDocumentFactory.buildDocument(InlineTaskSearchDocumentFactory.java:93) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexaction.AddSearchDocumentForInlineTaskAction.<init>(AddSearchDocumentForInlineTaskAction.java:30) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer.getAddSearchDocumentAction(FullReIndexer.java:202) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer.lambda$convertInlineTasksToIndexActions$3(FullReIndexer.java:169) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer$$Lambda/0x000001ba563472f8.apply(Unknown Source) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:1024) 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 com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer.convertInlineTasksToIndexActions(FullReIndexer.java:177) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer.indexNextBatchOfInlineTasks(FullReIndexer.java:132) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer.lambda$indexNextBatchOfInlineTasksInSeparateTransaction$0(FullReIndexer.java:104) at com.atlassian.confluence.plugins.tasklist.report.searchindex.indexmanagement.FullReIndexer$$Lambda/0x000001ba563469a8.doInTransaction(Unknown Source) at com.atlassian.sal.core.transaction.HostContextTransactionTemplate$1.doInTransaction(HostContextTransactionTemplate.java:21) at com.atlassian.sal.spring.component.SpringHostContextAccessor.lambda$doInTransaction$0(SpringHostContextAccessor.java:72) at com.atlassian.sal.spring.component.SpringHostContextAccessor$$Lambda/0x000001ba562bb2c0.doInTransaction(Unknown Source) at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) at com.atlassian.sal.spring.component.SpringHostContextAccessor.doInTransaction(SpringHostContextAccessor.java:70) at com.atlassian.sal.core.transaction.HostContextTransactionTemplate.execute(HostContextTransactionTemplate.java:18) at java.base/java.lang.invoke.LambdaForm$DMH/0x000001ba54346c00.invokeInterface(LambdaForm$DMH) at java.base/java.lang.invoke.LambdaForm$MH/0x000001ba572d8000.invoke(LambdaForm$MH) at java.base/java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder) 2025-09-12 11:04:04,188 WARN [Caesium-1-1] [impl.schedule.caesium.JobRunnerWrapper] runJob Scheduled job com.atlassian.confluence.plugins.confluence-inline-tasks:inlineTaskIndexQueueFlusherJob#flushTaskIndexQueue failed with response JobRunnerResponse[runOutcome=FAILED,message='Something went wrong with indexing: java.lang.OutOfMemoryError: Java heap space']
As seen:
- pool-15-thread-1 (a worker thread (numbers in the thread name may vary) that is spun up by a Caesium thread) reports a database-transaction-rollback
- Caesium-1-X (one of 4 scheduler threads that executes Confluence’s Scheduled Jobs (numbers in the thread name may differ))
- reports the actual java.lang.OutOfMemoryError: Java heap space message
- while executing the task report index flush job (Administration → Scheduled Jobs → scheduledjob.desc.flushTaskIndexQueue) (com.atlassian.confluence.plugins.confluence-inline-tasks:inlineTaskIndexQueueFlusherJob#flushTaskIndexQueue) where the stack trace references com.atlassian.confluence.plugins.tasklist.report.searchindex.InlineTaskSearchDocumentFactory’s getPageAncestors() method
The instance’s Java Garbage Collection (GC) logging (<installation-directory>/logs/gc*.log) will show an abrupt spike in memory usage, followed by stop-the-app/world full-GC events (seen as black bars in the graph below):
![]()
If the instance is running with the heap dump options enabled (or if a heap dump is taken manually at just the right time), then analyzing the heap dump using Eclipse’s Memory Analyzer Tool will show a significant chunk of the allocated java heap (-Xmx) being taken up by the pool thread spun up by the Caesium thread to flush the task index:
![]()
→ as seen above, 550+ MB of the allocated 1Gb heap (-Xmx) taken up by pool-15-thread-1
Digging into the problem suspect’s details, additional evidence of the cyclic reference is uncovered via the thread stack, as well as references to the actual content IDs:
![]()
As seen above, most of the heap is filled with many java.lang.Long objects containing the content ID numbers of the content involved in the cyclic loop, which in turn are being referenced by the pool thread that is executing com.atlassian.confluence.plugins.tasklist.report.searchindex.InlineTaskSearchDocumentFactory’s getPageAncestors() method.
Workaround
To stop this memory leak temporarily, navigate to Administration → Scheduled Jobs → click Disable on the scheduledjob.desc.flushTaskIndexQueue entry. This will allow the instance to remain online to execute any data-gathering steps if needed.
To fix the problem permanently:
- Identify the content IDs of the content involved in the cyclic loop (by noting the pages where the page-tree throws errors, or by finding the content IDs in the heap dump).
- Stop Confluence, backup the Confluence database, and then execute the following steps to break the cyclic loop:
- of the cyclic looped content-pair, based on looking at page-metadata (date created, date modified, author etc.), decide the desired hierarchical structure/layout
- for the page which should be the actual parent, set its parent ID to null:
update content set parentid=null where contentid=393229 ; - start Confluence
- login, and then navigate to the cyclic looped pages; they should now show the page-tree without the “Cyclic loop is detected” error
- in the Confluence space that hosts the affected pages, click on Space tools → Content Tools → Reorder Pages, and if necessary, move the affected content to match the desired content hierarchy