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

Thrown by NamespacedHierarchicalStore.rejectIfClosed() (line 498-503) as a NamespacedHierarchicalStoreException whenever any mutating or querying method is called after close() has been invoked. The store's closed flag is set in the finally of close(); after that, get/put/remove/computeIfAbsent/getOrComputeIfAbsent all reject. Closing is irreversible (close() is idempotent but cannot reopen).

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();

		@Nullable

View on GitHub (pinned to 956246301e)

Solutions

  1. Ensure all work that touches the Store completes before the extension/test method returns (join threads, cancel scheduled tasks).
  2. Do not retain Store/ExtensionContext references beyond their documented scope.
  3. If you need cross-test state, use a dedicated namespace in an engine-level store or an external mechanism, not a per-test store.
  4. Check store.isClosed() defensively before access in long-lived/background code paths.

Example fix

// before
private ExtensionContext.Store cached;
@BeforeEach void cache(ExtensionContext ctx) { this.cached = ctx.getStore(...); }
@AfterAll void useStoreAfterTests() { cached.get("x"); } // store for a prior test already closed -> throws

// after
@AfterEach void useStoreInScope(ExtensionContext ctx) {
    ExtensionContext.Store store = ctx.getStore(...); // fresh, in-scope
    store.get("x");
}
Defensive patterns

Strategy: validation

Validate before calling

if (store.isClosed()) {
    throw new IllegalStateException("store already closed; do not access out of scope");
}
Object value = store.get(MY_NS, key);

Type guard

static boolean isStoreUsable(ExtensionContext.Store store) {
    // ExtensionContext.Store does not expose isClosed; treat any post-test access as unsafe.
    // Only access within the callback that received the Store.
    return true; // scope discipline is the real guard
}

Try / catch

try {
    return store.get(MY_NS, key);
} catch (NamespacedHierarchicalStoreException e) {
    if (e.getMessage().contains("closed")) {
        // background work outlived the test; reschedule or skip
        log.debug("store closed; skipping stale access", e);
        return null;
    }
    throw e;
}

Prevention

When it happens

Trigger: An extension or engine code path holds a reference to an ExtensionContext.Store (backed by NamespacedHierarchicalStore) and tries to read/write it after the corresponding test/extension scope has finished (e.g. a background thread outliving the test, or an after-callback reusing a captured store). Parent/child store closing does not close each other, but the store for a finished test is closed.

Common situations: Async work started in a test method that touches the Store after @AfterEach; extension @AfterEach callbacks touching a store whose engine-level parent closed; caching a Store in a static field and reusing across tests; thread pools not joined before test completion.

Related errors


AI-assisted analysis of junit-team/junit5@956246301e (2026-08-04). Data as JSON: /data/errors/d80edc35df7df201.json. Report an issue: GitHub.