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

  1. Replace the unsupported operator with ':-': ${releaseUrl:https://default} style defaults
  2. Implement ':?' (fail if unset) semantics with maven-enforcer's requireProperty rule or a validating mojo instead of the expression
  3. 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

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


AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21). Data as JSON: /api/errors/521be79842b7ad01. Report an issue: GitHub.