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
- Construct UniqueId values programmatically: UniqueId.forEngine("junit-jupiter").append("test-class", MyTest.class.getName()) instead of concatenating strings.
- Verify the string shape: each segment must be '[' + type + ':' + value + ']', segments joined by '/'.
- If the value contains ':', '[', ']', or '/', it must be URL-encoded (the format does this on output); ensure you pass already-formatted ids.
- 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
- Build UniqueIds with UniqueId.forEngine(...).append(type, value) rather than string concatenation.
- Copy UniqueIds verbatim from launcher output rather than retyping.
- URL-encode segment values that may contain delimiters.
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
- Failed to create a java.net.URI from: ${uri}
- Failed to transform configuration parameter with key '%s' an
- Could not find any resource(s) with name: ${this.classpathRe
- Failed to retrieve canonical path for file: ${file}
- Failed to retrieve canonical path for directory: ${directory
AI-assisted analysis of junit-team/junit5@956246301e (2026-08-04).
Data as JSON: /data/errors/634a92886465f1aa.json.
Report an issue: GitHub.