{"record":{"id":"535aad2c58c85d35","repo":"apache/dolphinscheduler","slug":"could-not-resolve-placeholder","errorCode":null,"errorMessage":"Could not resolve placeholder '","messagePattern":"Could not resolve placeholder '","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/PropertyPlaceholderHelper.java","lineNumber":169,"sourceCode":"                        if (propVal == null) {\n                            propVal = defaultValue;\n                        }\n                    }\n                }\n                if (propVal != null) {\n                    // Recursive invocation, parsing placeholders contained in the\n                    // previously resolved placeholder value.\n                    propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);\n                    result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);\n                    if (log.isTraceEnabled()) {\n                        log.trace(\"Resolved placeholder '\" + placeholder + \"'\");\n                    }\n                    startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());\n                } else if (this.ignoreUnresolvablePlaceholders) {\n                    // Proceed with unprocessed value.\n                    startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());\n                } else {\n                    throw new IllegalArgumentException(\"Could not resolve placeholder '\"\n                            + placeholder + \"'\" + \" in value \\\"\" + value + \"\\\"\");\n                }\n                visitedPlaceholders.remove(originalPlaceholder);\n            } else {\n                startIndex = -1;\n            }\n        }\n\n        return result.toString();\n    }\n\n    private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {\n        int index = startIndex + this.placeholderPrefix.length();\n        int withinNestedPlaceholder = 0;\n        while (index < buf.length()) {\n            if (substringMatch(buf, index, this.placeholderSuffix)) {\n                if (withinNestedPlaceholder > 0) {\n                    withinNestedPlaceholder--;","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/PropertyPlaceholderHelper.java#L151-L187","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nString sql = helper.replacePlaceholders(\"SELECT * FROM t WHERE d='${bizdate}'\", resolver); // bizdate undefined\n// after\nprops.setProperty(\"bizdate\", \"20240101\"); // or define global param bizdate on the workflow\nString sql = helper.replacePlaceholders(\"SELECT * FROM t WHERE d='${bizdate}'\", resolver);","handlingStrategy":"validation","validationCode":"Matcher m = Pattern.compile(\"\\\\$\\\\{([^}]+)}\").matcher(raw);\nwhile (m.find()) { if (!params.containsKey(m.group(1))) throw new IllegalArgumentException(\"undefined param: \" + m.group(1)); }","typeGuard":null,"tryCatchPattern":"try { return helper.replacePlaceholders(value, resolver); } catch (IllegalArgumentException e) { log.error(\"unresolved placeholder in {}\", value, e); throw new TaskException(\"parameter resolution failed\", e); }","preventionTips":["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"],"tags":["placeholders","configuration","unresolved-variable"],"backgroundTag":"missing-config-value","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}