{"record":{"id":"172b45326e4078ce","repo":"quarkusio/quarkus","slug":"illegal-placeholder-in-maven-ci-friendly-version-p","errorCode":null,"errorMessage":"Illegal placeholder in Maven CI friendly version property \"${prop}\": ${resolved}\n\tPlease consult https://maven.apache.org/maven-ci-friendly.html#single-project-setup","messagePattern":"Illegal placeholder in Maven CI friendly version property \"(.+?)\": (.+?)\n\tPlease consult https://maven\\.apache\\.org/maven-ci-friendly\\.html#single-project-setup","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/ModelUtils.java","lineNumber":208,"sourceCode":"\n    public static boolean isUnresolvedVersion(String version) {\n        return getUnresolvedVersionPattern().matcher(version).find();\n    }\n\n    public static String resolveVersion(String rawVersion, Model rawModel) {\n        final Map<String, String> props = new HashMap<>(rawModel.getProperties().size() + System.getProperties().size());\n        putAll(props, rawModel.getProperties());\n        putAll(props, System.getProperties());\n\n        Matcher matcher = getUnresolvedVersionPattern().matcher(rawVersion);\n        StringBuilder sb = new StringBuilder();\n        while (matcher.find()) {\n            final String resolved = props.get(matcher.group(1));\n            if (resolved == null) {\n                return null;\n            }\n            if (resolved.contains(\"${\")) {\n                throw new IllegalArgumentException(\"Illegal placeholder in Maven CI friendly version property \\\"\"\n                        + matcher.group(1) + \"\\\": \" + resolved\n                        + \"\\n\\tPlease consult https://maven.apache.org/maven-ci-friendly.html#single-project-setup\");\n            }\n            matcher.appendReplacement(sb, resolved);\n        }\n        matcher.appendTail(sb);\n        return sb.toString();\n    }\n\n    private static void putAll(Map<String, String> map, Properties props) {\n        for (Map.Entry<Object, Object> e : props.entrySet()) {\n            map.put(e.getKey().toString(), e.getValue().toString());\n        }\n    }\n\n    /**\n     * If the model contains properties, this method overrides those that appear to be\n     * defined as system properties.","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/ModelUtils.java#L190-L226","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"<!-- before -->\n<properties>\n  <revision>${project.version}</revision>\n</properties>\n<version>${revision}</version>\n<!-- after -->\n<properties>\n  <revision>1.0.0-SNAPSHOT</revision>\n</properties>\n<version>${revision}</version>","handlingStrategy":"validation","validationCode":"String rev = model.getProperties().getProperty(\"revision\");\nif (model.getVersion() != null && model.getVersion().contains(\"${revision}\")\n        && (rev == null || rev.contains(\"${\"))) {\n    throw new IllegalArgumentException(\n        \"Set -Drevision=<value> or a literal <revision> property in the pom\");\n}","typeGuard":"static boolean hasResolvableCiFriendlyVersion(Model model) {\n    String v = model.getVersion();\n    if (v == null || !v.contains(\"${\")) return true;\n    for (String p : new String[]{\"revision\", \"sha1\", \"changelist\"}) {\n        if (v.contains(\"${\" + p + \"}\")) {\n            String val = model.getProperties().getProperty(p);\n            if (val == null || val.contains(\"${\")) return false;\n        }\n    }\n    return true;\n}","tryCatchPattern":"try {\n    String version = ModelUtils.getVersion(model);\n} catch (IllegalArgumentException e) {\n    // nested/unresolved CI-friendly placeholder; advise flattening or -D override\n}","preventionTips":["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."],"tags":["maven","ci-friendly-version","property-resolution","quarkus-bootstrap"],"backgroundTag":"unresolved-maven-property","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}