apache/dolphinscheduler · error · IllegalArgumentException
Could not resolve placeholder '
Error message
Could not resolve placeholder '
What it means
PropertyPlaceholderHelper throws this when a ${placeholder} in a value cannot be resolved by any supplied PropertyResolver and ignoreUnresolvablePlaceholders is false. The raw value is returned unexpanded instead of being silently passed through, since leaving unknown ${...} in task parameters is usually a bug. The message names the unresolvable placeholder and the value containing it.
Source
Thrown at dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/PropertyPlaceholderHelper.java:169
if (propVal == null) {
propVal = defaultValue;
}
}
}
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (log.isTraceEnabled()) {
log.trace("Resolved placeholder '" + placeholder + "'");
}
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
} else if (this.ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
} else {
throw new IllegalArgumentException("Could not resolve placeholder '"
+ placeholder + "'" + " in value \"" + value + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
} else {
startIndex = -1;
}
}
return result.toString();
}
private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
int index = startIndex + this.placeholderPrefix.length();
int withinNestedPlaceholder = 0;
while (index < buf.length()) {
if (substringMatch(buf, index, this.placeholderSuffix)) {
if (withinNestedPlaceholder > 0) {
withinNestedPlaceholder--;View on GitHub (pinned to 02eac45a1b)
Solutions
- Read the placeholder name in the message and define it in the task's local/custom parameters or as a global parameter on the workflow.
- Fix typos and case-sensitivity: placeholder names are resolved exactly against the parameter map.
- Verify the time/builtin parameter you expect is generated for that task type; use the format actually supported (e.g. $[yyyyMMdd] for time expressions vs ${var} for properties).
- If the placeholder is intended to stay literal, construct the helper with ignoreUnresolvablePlaceholders=true.
- Check upstream parameter passing (dependent/passthrough params) — the parent task may not have produced the parameter.
Example fix
// before
String sql = helper.replacePlaceholders("SELECT * FROM t WHERE d='${bizdate}'", resolver); // bizdate undefined
// after
props.setProperty("bizdate", "20240101"); // or define global param bizdate on the workflow
String sql = helper.replacePlaceholders("SELECT * FROM t WHERE d='${bizdate}'", resolver); Defensive patterns
Strategy: validation
Validate before calling
Matcher m = Pattern.compile("\\$\\{([^}]+)}").matcher(raw);
while (m.find()) { if (!params.containsKey(m.group(1))) throw new IllegalArgumentException("undefined param: " + m.group(1)); } Try / catch
try { return helper.replacePlaceholders(value, resolver); } catch (IllegalArgumentException e) { log.error("unresolved placeholder in {}", value, e); throw new TaskException("parameter resolution failed", e); } Prevention
- Define every ${name} used in task SQL/scripts as a local or global parameter
- Watch for typos and exact-case matches between usage and definition
- Confirm builtin/system params are injected for the task type in use
- Use ignoreUnresolvablePlaceholders=true only when literal ${...} output is intended
When it happens
Trigger: Calling replacePlaceholders/parseStringValue on a string containing ${name} where no property named 'name' exists in the resolver (local params, global params, or builtin time params); a typo like ${dateime} instead of ${datetime}; a placeholder that nested-resolution turned into a key absent from the parameter map.
Common situations: Task parameters referencing a global parameter that was deleted or renamed; system/builtin params (e.g. ${system.biz.date}) not injected in the execution context; user-defined params with case mismatches; switching task types so previously-defined params disappear.
Understand the failure class
Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.
Related errors
- Circular placeholder reference '' in property definitions
- receivers must not be null
- url can not be null
- headerParams is not a valid json
- bodyParams is not a valid json
AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06).
Data as JSON: /api/errors/535aad2c58c85d35.
Report an issue: GitHub.