{"id":"f352784df77264fd","repo":"junit-team/junit5","slug":"task-was-deferred-but-should-have-been-executed-sy","errorCode":null,"errorMessage":"Task was deferred but should have been executed synchronously: ${testTask}","messagePattern":"Task was deferred but should have been executed synchronously: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java","lineNumber":242,"sourceCode":"\t\t *\n\t\t * @return {@code null} always\n\t\t */\n\t\t@Override\n\t\tpublic final Void getRawResult() {\n\t\t\treturn null;\n\t\t}\n\n\t\t/**\n\t\t * Requires null completion value.\n\t\t */\n\t\t@Override\n\t\tprotected final void setRawResult(Void mustBeNull) {\n\t\t}\n\n\t\tvoid execSync() {\n\t\t\tboolean completed = exec();\n\t\t\tif (!completed) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Task was deferred but should have been executed synchronously: \" + testTask);\n\t\t\t}\n\t\t}\n\n\t\t@SuppressWarnings(\"try\")\n\t\t@Override\n\t\tpublic boolean exec() {\n\t\t\t// Check if this task is compatible with the current resource lock, if there is any.\n\t\t\t// If not, we put this task in the thread local as a deferred task\n\t\t\t// and let the worker thread fork it once it is done with the current task.\n\t\t\tResourceLock resourceLock = testTask.getResourceLock();\n\t\t\tThreadLock threadLock = threadLocks.get();\n\t\t\tif (!threadLock.areAllHeldLocksCompatibleWith(resourceLock)) {\n\t\t\t\tthreadLock.addDeferredTask(this);\n\t\t\t\ttaskEventListener.deferred(testTask);\n\t\t\t\t// Return false to indicate that this task is not done yet\n\t\t\t\t// this means that .join() will wait.\n\t\t\t\treturn false;","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/junit-team/junit5/blob/956246301e03d757539f7b76dd5a91f298637563/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java#L224-L260","documentation":"Thrown as IllegalStateException by ExclusiveTask.execSync() (line 239-245) when exec() returns false. exec() returns false only when the task's resource lock is incompatible with locks already held on the current thread, so the task is deferred instead of run. execSync() is called for SAME_THREAD tasks and single-task invokeAll where deferral is not allowed; hence 'should have been executed synchronously'.","triggerScenarios":"A SAME_THREAD test task (or the lone task in an invokeAll) cannot acquire its ResourceLock because the current worker thread already holds an incompatible lock (e.g. a child needs GLOBAL_READ_WRITE while the parent holds a read-write lock). This is an internal invariant violation in the ForkJoinPool executor's lock bookkeeping.","commonSituations":"Engine/extension bugs mixing @ResourceLock annotations with SAME_THREAD execution mode in ways the executor cannot satisfy; @Isolated tests nested inside concurrently-executing parents in the ForkJoinPool executor; corner cases with custom Node.task implementations returning conflicting resource locks.","solutions":["Review @ResourceLock / @Isolated usage on the tests involved in the failure; likely a lock combination that cannot run on the same thread.","Avoid SAME_THREAD execution mode for tests that require mutually exclusive resources with their parents; use CONCURRENT or move them to separate classes.","If using ForkJoinPoolHierarchicalTestExecutorService (deprecated since 6.1), switch to the WORKER_THREAD_POOL executor which handles lock contention differently.","Report a JUnit bug if the lock/resource configuration is legitimate; the message indicates an executor-internal invariant was violated."],"exampleFix":"// before: conflicting locks with same-thread parent\n@Execution(ExecutionMode.SAME_THREAD)\n@ResourceLock(value = \"shared\", mode = Mode.READ_WRITE)\nclass MyNestedTest { ... } // triggers deferral in ForkJoinPool executor\n\n// after: drop the rigid lock or execution mode\n@Execution(ExecutionMode.CONCURRENT)\nclass MyNestedTest { ... }","handlingStrategy":"validation","validationCode":"// Ensure SAME_THREAD tests do not require resources incompatible with their parent's locks\n// In test code: avoid combining @Execution(SAME_THREAD) with @ResourceLock(mode=READ_WRITE)\n// on a resource the parent already locks exclusively.","typeGuard":null,"tryCatchPattern":"try {\n    testTask.execute();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"deferred but should have been executed\")) {\n        // log and fall back to CONCURRENT execution or disable parallelism\n    }\n    throw e;\n}","preventionTips":["Avoid SAME_THREAD mode for tests whose resource locks conflict with their container's locks.","Prefer the WORKER_THREAD_POOL executor over the deprecated ForkJoinPool one (6.1+).","Report legitimate lock combinations that trigger this as a JUnit bug."],"tags":["junit-platform","parallel-execution","fork-join-pool","resource-lock","threading","engine-internal"],"analyzedSha":"956246301e03d757539f7b76dd5a91f298637563","analyzedAt":"2026-08-04T19:25:17.049Z","schemaVersion":2}