junit-team/junit5 · error · JUnitException

'%s' is not a well-formed UniqueId segment

Error message

'%s' is not a well-formed UniqueId segment

What it means

Thrown by UniqueIdFormat.createSegment (line 94-102) when a single segment string fails to match the segment regex built from the open/typeValueSeparator/close delimiters (default '[', ':', ']'). UniqueId.parse (line 88) splits on '/' and parses each segment; any segment not matching the well-formed '[type:value]' pattern raises a JUnitException. This guards the integrity of the UniqueId segment format used throughout the engine.

Source

Thrown at junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueIdFormat.java:97

		encodedCharacterMap.computeIfAbsent(segmentDelimiter, UniqueIdFormat::encode);
	}

	/**
	 * Parse a {@code UniqueId} from the supplied string representation.
	 *
	 * @return a properly constructed {@code UniqueId}
	 * @throws JUnitException if the string cannot be parsed
	 */
	UniqueId parse(String source) throws JUnitException {
		String[] parts = source.split(String.valueOf(this.segmentDelimiter));
		List<Segment> segments = Arrays.stream(parts).map(this::createSegment).toList();
		return new UniqueId(segments);
	}

	private Segment createSegment(String segmentString) throws JUnitException {
		Matcher segmentMatcher = this.segmentPattern.matcher(segmentString);
		if (!segmentMatcher.matches()) {
			throw new JUnitException("'%s' is not a well-formed UniqueId segment".formatted(segmentString));
		}
		String type = decode(checkAllowed(segmentMatcher.group(1)));
		String value = decode(checkAllowed(segmentMatcher.group(2)));
		return new Segment(type, value);
	}

	private String checkAllowed(String typeOrValue) {
		checkDoesNotContain(typeOrValue, this.segmentDelimiter);
		checkDoesNotContain(typeOrValue, this.typeValueSeparator);
		checkDoesNotContain(typeOrValue, this.openSegment);
		checkDoesNotContain(typeOrValue, this.closeSegment);
		return typeOrValue;
	}

	private void checkDoesNotContain(String typeOrValue, char forbiddenCharacter) {
		Preconditions.condition(typeOrValue.indexOf(forbiddenCharacter) < 0,
			() -> "type or value '%s' must not contain '%s'".formatted(typeOrValue, forbiddenCharacter));
	}

View on GitHub (pinned to 956246301e)

Solutions

  1. Construct UniqueId values programmatically: UniqueId.forEngine("junit-jupiter").append("test-class", MyTest.class.getName()) instead of concatenating strings.
  2. Verify the string shape: each segment must be '[' + type + ':' + value + ']', segments joined by '/'.
  3. If the value contains ':', '[', ']', or '/', it must be URL-encoded (the format does this on output); ensure you pass already-formatted ids.
  4. Copy the UniqueId verbatim from the failure report / launcher output rather than retyping it.

Example fix

// before
UniqueId id = UniqueId.parse("[engine:junit-jupiter]/MyTest#myTest"); // '#' segment is malformed

// after
UniqueId id = UniqueId.parse("[engine:junit-jupiter]/[class:com.example.MyTest]/[method:myTest()]");
// or better, build it:
UniqueId id = UniqueId.forEngine("junit-jupiter")
    .append("class", "com.example.MyTest")
    .append("method", "myTest()");
Defensive patterns

Strategy: try-catch

Validate before calling

static boolean isWellFormed(String id) {
    if (id == null || id.isBlank()) return false;
    return java.util.Arrays.stream(id.split("/"))
        .allMatch(s -> s.matches("\\[[^\\[\\]:]+:[^\\[\\]:]+\\]"));
}

Try / catch

try {
    return UniqueId.parse(raw);
} catch (JUnitException e) {
    throw new IllegalArgumentException("Invalid UniqueId string: " + raw, e);
}

Prevention

When it happens

Trigger: Calling UniqueId.parse on a malformed string, or selecting by UniqueId via a UniqueIdSelector built from a malformed string, where a segment lacks brackets, lacks the colon, has empty type or value, or contains stray delimiters. Common with copy-paste errors of test ids from logs/IDE.

Common situations: Passing a truncated UniqueId string (e.g. dropping the leading '['); using a logical display name instead of the machine segment; URL-decoding a segment incorrectly so delimiters reappear; building UniqueId strings by hand instead of via UniqueId.forEngine/append.

Related errors


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