junit-team/junit5 · error · ExtensionConfigurationException

SystemPropertiesExtension was configured to restore the…

Error message

SystemPropertiesExtension was configured to restore the system properties by [%s]. However, it was not possible to create an accurate snapshot of the system properties using Properties::clone, because default properties were present: %s

What it means

ExtensionConfigurationException from JupiterPropertyUtils.throwIfHasObservableDefaults, raised when the SystemPropertiesExtension is asked to snapshot/restore system properties but the current Properties object has observable default properties (entries reachable only via stringPropertyNames() but not in the main keySet()). Because Properties.clone() does not copy defaults, a restore would silently lose those default-backed entries, so JUnit refuses rather than produce an inaccurate snapshot.

Solutions

  1. Avoid setting System.getProperties() defaults before the test; use explicit System.setProperty() entries which the extension can snapshot correctly.
  2. If defaults are required, set them after the extension's snapshot is taken, or clear them before the test runs.
  3. Disable restore behavior for the affected property set if accurate snapshotting is impossible in your environment.

Example fix

// before
Properties p = System.getProperties();
p.defaults = new Properties(Map.of("legacy.flag", "1"));
// after
System.setProperty("legacy.flag", "1"); // snapshot-able
Defensive patterns

Strategy: validation

Validate before calling

Properties p = System.getProperties();
Set<Object> keys = p.keySet();
List<String> defaults = p.stringPropertyNames().stream()
        .filter(n -> !keys.contains(n)).toList();
if (!defaults.isEmpty()) { /* clear defaults before snapshot */ }

Prevention

When it happens

Trigger: Test code or a prior extension calls System.getProperties().defaults = ... (or sets defaults via a Properties subclass) before the SystemPropertiesExtension tries to capture the snapshot for restoration.

Common situations: A @BeforeEach or static initializer that seeds System properties with defaults; third-party libraries (logging, config libs) that install default system properties; chaining Properties objects for layered lookups.

Related errors


AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11). Data as JSON: /api/errors/e469c81b4d2a696a. Report an issue: GitHub.

Appendix: source

Thrown at junit-jupiter-api/src/main/java/org/junit/jupiter/api/util/JupiterPropertyUtils.java:41

		/* no-op */
	}

	static Properties cloneWithoutDefaults(ExtensionContext context, Properties properties) {
		// Custom implementations have to implement clone correctly.
		if (properties.getClass() == Properties.class) {
			throwIfHasObservableDefaults(context, properties);
		}
		return (Properties) properties.clone();
	}

	private static void throwIfHasObservableDefaults(ExtensionContext context, Properties properties) {
		Set<Object> keySet = properties.keySet();
		// A best effort check.
		List<String> defaultPropertyNames = properties.stringPropertyNames().stream() //
				.filter(propertyName -> !keySet.contains(propertyName)) //
				.toList();
		if (!defaultPropertyNames.isEmpty()) {
			throw new ExtensionConfigurationException("""
					SystemPropertiesExtension was configured to restore the system properties by [%s]. \
					However, it was not possible to create an accurate snapshot of the system properties \
					using Properties::clone, because default properties were present: %s""" //
					.formatted(context.getElement().orElseThrow(), defaultPropertyNames));
		}
	}

}

View on GitHub (pinned to f070c699a0)