quarkusio/quarkus · error · IllegalArgumentException
Illegal placeholder in Maven CI friendly version property "$
Error message
Illegal placeholder in Maven CI friendly version property "${prop}": ${resolved}
Please consult https://maven.apache.org/maven-ci-friendly.html#single-project-setup What it means
ModelUtils.resolveVersion expands CI-friendly version properties (${revision}, ${sha1}, ${changelist}) using the model properties and system properties. If a resolved property value itself contains `${...}` (a nested/unresolved placeholder), the version would still not be concrete, so it throws IllegalArgumentException with a pointer to Maven's CI-friendly docs.
Source
Thrown at independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/ModelUtils.java:208
public static boolean isUnresolvedVersion(String version) {
return getUnresolvedVersionPattern().matcher(version).find();
}
public static String resolveVersion(String rawVersion, Model rawModel) {
final Map<String, String> props = new HashMap<>(rawModel.getProperties().size() + System.getProperties().size());
putAll(props, rawModel.getProperties());
putAll(props, System.getProperties());
Matcher matcher = getUnresolvedVersionPattern().matcher(rawVersion);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
final String resolved = props.get(matcher.group(1));
if (resolved == null) {
return null;
}
if (resolved.contains("${")) {
throw new IllegalArgumentException("Illegal placeholder in Maven CI friendly version property \""
+ matcher.group(1) + "\": " + resolved
+ "\n\tPlease consult https://maven.apache.org/maven-ci-friendly.html#single-project-setup");
}
matcher.appendReplacement(sb, resolved);
}
matcher.appendTail(sb);
return sb.toString();
}
private static void putAll(Map<String, String> map, Properties props) {
for (Map.Entry<Object, Object> e : props.entrySet()) {
map.put(e.getKey().toString(), e.getValue().toString());
}
}
/**
* If the model contains properties, this method overrides those that appear to be
* defined as system properties.View on GitHub (pinned to e1c734241f)
Solutions
- Run Maven with the property set explicitly, e.g. `mvn -Drevision=1.0.0 package` or export it as a system property so the bootstrap can resolve it.
- Replace the nested placeholder with a literal value in the pom.xml (e.g. `<revision>1.0.0-SNAPSHOT</revision>`).
- Use the Maven flatten plugin (flatten-maven-plugin with `resolveCiFriendliesOnly`) so the installed/parsed model contains a concrete version.
- Follow https://maven.apache.org/maven-ci-friendly.html#single-project-setup for a valid CI-friendly setup.
Example fix
<!-- before -->
<properties>
<revision>${project.version}</revision>
</properties>
<version>${revision}</version>
<!-- after -->
<properties>
<revision>1.0.0-SNAPSHOT</revision>
</properties>
<version>${revision}</version> Defensive patterns
Strategy: validation
Validate before calling
String rev = model.getProperties().getProperty("revision");
if (model.getVersion() != null && model.getVersion().contains("${revision}")
&& (rev == null || rev.contains("${"))) {
throw new IllegalArgumentException(
"Set -Drevision=<value> or a literal <revision> property in the pom");
} Type guard
static boolean hasResolvableCiFriendlyVersion(Model model) {
String v = model.getVersion();
if (v == null || !v.contains("${")) return true;
for (String p : new String[]{"revision", "sha1", "changelist"}) {
if (v.contains("${" + p + "}")) {
String val = model.getProperties().getProperty(p);
if (val == null || val.contains("${")) return false;
}
}
return true;
} Try / catch
try {
String version = ModelUtils.getVersion(model);
} catch (IllegalArgumentException e) {
// nested/unresolved CI-friendly placeholder; advise flattening or -D override
} Prevention
- Never chain CI-friendly version properties (revision -> another property).
- Pass -Drevision=... on the command line or define literal values in <properties>.
- Use flatten-maven-plugin with resolveCiFriendliesOnly for CI-friendly setups.
- Follow the maven-ci-friendly.html single-project-setup pattern.
When it happens
Trigger: A pom.xml with e.g. `<version>${revision}</version>` and `<revision>${another}</revision>` where `another` is not defined, or where a property value chains into another placeholder; calling resolveVersion/getVersion on such a raw model.
Common situations: Migrating to CI-friendly versions (`revision/changelist/sha1`) without flattening or passing `-Drevision=...`; defining the property via a parent POM not on disk or via settings.xml in a raw-model context; typos in property names causing fallback values containing placeholders; using CI-friendly versions in a Quarkus dev-mode app where Maven's flatten step is skipped.
Related errors
- Failed to initialize deployment dependencies resolver
- Failed to locate project pom.xml for ${path}
- Failed to located META-INF/maven/<groupId>/<artifactId>/pom.
- Failed to determine groupId for project model
- Failed to determine version for project model
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/172b45326e4078ce.
Report an issue: GitHub.