apache/maven · error · InterpolatorException
Bad substitution operator in: ${variable}
Error message
Bad substitution operator in: ${variable} What it means
The Maven interpolator (DefaultInterpolator) supports only two substitution operators inside ${...} expressions: ':-' (use the following value when the variable is unset or empty) and ':+ ' (use the following value when the variable is set). When an expression contains an operator segment that is neither of these — Bash-style expansions such as ':=', ':?', ':#' — the interpolation fails with InterpolatorException("Bad substitution operator in: ${...}").
Source
Thrown at impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultInterpolator.java:345
// Process the operator value through substitution if it contains variables
String processedOpValue = doSubstVars(
opValue, variable, cycleMap, configProps, callback, postprocessor, defaultsToEmptyString);
// Apply the operator
if (":+".equals(op)) {
if (substValue != null && !substValue.isEmpty()) {
substValue = processedOpValue;
// Skip any remaining operators since we've made a decision
break;
}
} else if (":-".equals(op)) {
if (substValue == null || substValue.isEmpty()) {
substValue = processedOpValue;
// Skip any remaining operators since we've made a decision
break;
}
} else {
throw new InterpolatorException("Bad substitution operator in: ${" + variable + "}");
}
startIdx = nextIdx >= 0 ? nextIdx : variable.length();
}
if (substValue == null) {
if (defaultsToEmptyString) {
substValue = "";
} else {
substValue = MARKER + "{" + variable + "}";
}
}
return substValue;
}
private static String resolveVariable(
String variable,View on GitHub (pinned to e4093d4e12)
Solutions
- Replace the unsupported operator with ':-': ${releaseUrl:https://default} style defaults
- Implement ':?' (fail if unset) semantics with maven-enforcer's requireProperty rule or a validating mojo instead of the expression
- Move complex conditional logic into profiles activated by property presence/absence
Example fix
<!-- before -->
<url>${releaseUrl:?releaseUrl must be set}</url>
<!-- after -->
<url>${releaseUrl:-https://repo.example.com/releases}</url> Defensive patterns
Strategy: validation
Validate before calling
// lint property expressions: only ':-' and ':+' operators are supported
static final Pattern BAD_OP = Pattern.compile("\\$\\{[^}]*:[-+?=#@%][^}]*}");
static void checkExpressions(String pomText) {
Matcher m = BAD_OP.matcher(pomText);
if (m.find()) throw new IllegalArgumentException("Unsupported operator in expression: " + m.group());
} Prevention
- Use only ${var:-default} and ${var:+alternate} forms in pom.xml and settings.xml
- Express 'fail if unset' with maven-enforcer requireProperty, not ':?' syntax
- Lint property expressions in CI so shell-style operators never reach the interpolator
When it happens
Trigger: A pom.xml or settings property using ${releaseUrl:?releaseUrl must be set} or ${skipTests:=false} in any field the model interpolator processes; shell parameter-expansion syntax copied from scripts into Maven properties.
Common situations: Porting shell scripts or Dockerfile ARG defaults into Maven properties; developers assuming full Bash parameter expansion works in pom.xml; typos like ${v:-} vs ${v::-} producing an unexpected operator segment.
Related errors
- Repository list contains duplicate entries. Each repository
- Cannot read project model from interpolating filter of seria
- Unable to parse unicode value: {}
- Cannot evaluate expression '%s' for configuration entry '%s'
- recursive variable reference: ${variable}
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/521be79842b7ad01.
Report an issue: GitHub.