junit-team/junit5 · error · NamespacedHierarchicalStoreException
A NamespacedHierarchicalStore cannot be modified or queried…
Error message
A NamespacedHierarchicalStore cannot be modified or queried after it has been closed
What it means
NamespacedHierarchicalStore rejects every get/put/remove operation after close() has been called via rejectIfClosed(). The store backs LauncherSession/ExtensionContext scoped data; closing the owning session/context invalidates it. Any later access is a use-after-close bug.
Solutions
- Do not retain store references beyond the scope that owns them (the ExtensionContext/LauncherSession lifetime).
- If you must cache, copy values out of the store before the context closes (via a BeforeAllCallback/AfterAllCallback that runs while the store is open).
- Ensure you are not double-closing or sharing a LauncherSession across independent runs.
Example fix
// before - extension caches the store in a field
private Store store;
void beforeAll(ExtensionContext ctx) { store = ctx.getStore(...); }
void afterAll() { store.put("done", true); } // ctx closed -> throws
// after - use the context each time
void afterAll(ExtensionContext ctx) { ctx.getStore(...).put("done", true); } Defensive patterns
Strategy: validation
Validate before calling
// Track lifecycle: only touch the store while the owning context is open
if (sessionClosed) throw new IllegalStateException("store closed");
store.get(namespace, key, type); Try / catch
try {
store.put(namespace, key, value);
} catch (NamespacedHierarchicalStoreException e) {
if (e.getMessage().contains("closed")) {
// session/context gone: drop the write, do not retain the store
}
} Prevention
- Never store NamespacedHierarchicalStore references in static/long-lived fields.
- Access the store only through the live ExtensionContext / LauncherSession.
- Copy data out before the owning context closes.
When it happens
Trigger: Calling any mutating or querying method on a NamespacedHierarchicalStore after store.close() ran. Happens when an ExtensionContext or LauncherSession is closed but code retains a reference to its store and reads/writes it later (e.g. an extension that caches the store in a static or long-lived field).
Common situations: An extension stored the ExtensionContext.getStore() reference and uses it after the test/class finished; a LauncherSession scoped bean accessed after LauncherSession.close(); a listener that holds store state past the session; reuse of a closed EngineContext in a new test run.
Related errors
AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11).
Data as JSON: /api/errors/d80edc35df7df201.
Report an issue: GitHub.
Appendix: source
Thrown at junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java:500
}
@SuppressWarnings("unchecked")
private <T, V> T castNonNullToRequiredType(Object key, V value, Class<T> requiredType) {
if (isAssignableTo(value, requiredType)) {
if (requiredType.isPrimitive()) {
return (T) requireNonNull(getWrapperType(requiredType)).cast(value);
}
return requiredType.cast(value);
}
// else
throw new NamespacedHierarchicalStoreException(
"Object stored under key [%s] is not of required type [%s], but was [%s]: %s".formatted(key,
requiredType.getName(), value.getClass().getName(), value));
}
private void rejectIfClosed() {
if (this.closed) {
throw new NamespacedHierarchicalStoreException(
"A NamespacedHierarchicalStore cannot be modified or queried after it has been closed");
}
}
private record CompositeKey<N>(N namespace, Object key) {
CompositeKey {
Preconditions.notNull(namespace, "namespace must not be null");
Preconditions.notNull(key, "key must not be null");
}
}
private interface StoredValue {
int order();
@NullableView on GitHub (pinned to f070c699a0)