{"record":{"id":"752ab2547d1deaf0","repo":"apache/maven","slug":"cannot-access-outside-of-a-scoping-block","errorCode":null,"errorMessage":"Cannot access {} outside of a scoping block","messagePattern":"Cannot access (.+?) outside of a scoping block","errorType":"exception","errorClass":"DIException","httpStatus":null,"severity":"error","filePath":"impl/maven-impl/src/main/java/org/apache/maven/impl/di/MojoExecutionScope.java","lineNumber":105,"sourceCode":"        }\n    }\n\n    public <T> void seed(Class<T> clazz, Supplier<T> value) {\n        getScopeState().seed(clazz, value);\n    }\n\n    public <T> void seed(Class<T> clazz, final T value) {\n        seed(clazz, (Supplier<T>) () -> value);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Nonnull\n    @Override\n    public <T> Supplier<T> scope(@Nonnull Key<T> key, @Nonnull Supplier<T> unscoped) {\n        return () -> {\n            LinkedList<ScopeState> stack = values.get();\n            if (stack == null || stack.isEmpty()) {\n                throw new DIException(\"Cannot access \" + key + \" outside of a scoping block\");\n            }\n\n            ScopeState state = stack.getFirst();\n\n            Supplier<?> seeded = state.seeded.get(key);\n\n            if (seeded != null) {\n                return (T) seeded.get();\n            }\n\n            T provided = (T) state.provided.get(key);\n            if (provided == null && unscoped != null) {\n                provided = unscoped.get();\n                state.provided.put(key, provided);\n            }\n\n            return provided;\n        };","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/apache/maven/blob/e4093d4e120eac99d6bdce5ba67cace2f3085c97/impl/maven-impl/src/main/java/org/apache/maven/impl/di/MojoExecutionScope.java#L87-L123","documentation":"MojoExecutionScope.scope(key, unscoped) returns a supplier that first checks the thread-local stack of ScopeState created by enter(). If no scoping block is active (stack null or empty — enter() never called on this thread, or exit() already ran), resolving any mojo-scoped key throws DIException(\"Cannot access ... outside of a scoping block\"). Mojo-scoped objects exist only inside Maven's mojo execution window.","triggerScenarios":"Resolving a MojoExecutionScope-scoped binding from a different thread than the one that called enter(); resolving after exit() has popped the state; looking up mojo-scoped types during plugin metadata parsing rather than execution.","commonSituations":"Parallel builds moving work onto executor threads; asynchronous code (CompletableFuture, custom thread pools) touching scoped beans; tests forgetting the enter()/exit() bracket; lazy suppliers evaluated after the mojo finished.","solutions":["Perform all lookups of mojo-scoped objects on the execution thread, inside the scoped block","In tests, bracket the code: scope.enter(); try { ... } finally { scope.exit(); }","Capture the needed instances as plain fields before going asynchronous instead of resolving scoped keys off-thread"],"exampleFix":"// before: resolving mojo-scoped bean off-thread\nexecutor.submit(() -> injector.getInstance(MyComponent.class)); // DIException\n\n// after: capture inside the scope, use plain object off-thread\nMyComponent c = injector.getInstance(MyComponent.class); // on execution thread\nexecutor.submit(() -> c.doWork());","handlingStrategy":"validation","validationCode":"// structure code so scoped resolution happens inside the scoping block\nmojoExecutionScope.enter();\ntry {\n    MyComponent c = injector.getInstance(MyComponent.class); // scope active on this thread\n    doWork(c);\n} finally {\n    mojoExecutionScope.exit();\n}","typeGuard":null,"tryCatchPattern":"try {\n    return injector.getInstance(MyComponent.class);\n} catch (DIException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"outside of a scoping block\")) {\n        // re-dispatch the work onto the execution thread inside the scope\n        return callInsideMojoScope(() -> injector.getInstance(MyComponent.class));\n    }\n    throw e;\n}","preventionTips":["Resolve mojo-scoped beans only on the execution thread inside enter()/exit()","Capture instances into plain fields before handing work to other threads","In tests, always wrap with scope.enter() ... finally scope.exit()"],"tags":["maven","di","sisu","scope","threading"],"backgroundTag":"di-scope-not-entered","analyzedSha":"e4093d4e120eac99d6bdce5ba67cace2f3085c97","analyzedAt":"2026-08-21T22:58:24.034Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}