apache/dolphinscheduler · error · EmrServerlessTaskException

Failed to resolve parameter placeholders

Error message

Failed to resolve parameter placeholders

What it means

buildStartJobRunRequest resolves ${placeholders} in the user-supplied startJobRunRequestJson via ParameterUtils.convertParameterPlaceholders. Any exception during placeholder substitution is wrapped as EmrServerlessTaskException with this message, so the request JSON is never sent to AWS.

Solutions

  1. Inspect the 'caused by' for the exact placeholder parse failure position
  2. Fix the placeholder syntax in startJobRunRequestJson — every '${...}' must be closed and reference a defined parameter
  3. Verify local/global parameters the placeholders refer to are defined on the workflow/task
  4. Simplify: log or echo the rendered JSON in a shell task first to confirm substitution works

Example fix

// before
"entryPoint": "s3://bucket/${system.biz.date' // unterminated placeholder
// after
"entryPoint": "s3://bucket/${system.biz.date}/job.py" // closed, valid reference
Defensive patterns

Strategy: validation

Validate before calling

// validate placeholders resolve before submitting
String json = emrServerlessParameters.getStartJobRunRequestJson();
if (json != null && (json.contains("${") && !json.matches("(?s).*\\$\\\\{[^}]*\\}.*"))) {
    throw new IllegalArgumentException("Unbalanced placeholder in startJobRunRequestJson");
}
String resolved = ParameterUtils.convertParameterPlaceholders(json,
    ParameterUtils.convert(taskExecutionContext.getPrepareParamsMap()));
if (resolved.contains("${")) log.warn("Unresolved placeholder remains in rendered JSON");

Try / catch

try {
    buildStartJobRunRequest();
} catch (EmrServerlessTaskException e) {
    if (e.getMessage().contains("Failed to resolve parameter placeholders")) {
        log.error("Check '${...}' syntax and referenced parameter definitions", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: ParameterUtils.convertParameterPlaceholders throws on the startJobRunRequestJson or on converting prepareParamsMap — malformed placeholder syntax like an unterminated '${', a null startJobRunRequestJson, or unsupported escape sequences in the template.

Common situations: User wrote '${var' without closing brace in the task JSON; a business/launch date parameter name mismatched so substitution logic fails; taskParams JSON contains characters the parameter engine cannot process.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/e1caf8bc9f9f400f. Report an issue: GitHub.

Appendix: source

Thrown at dolphinscheduler-task-plugin/dolphinscheduler-task-emr-serverless/src/main/java/org/apache/dolphinscheduler/plugin/task/emrserverless/EmrServerlessTask.java:219

        return Collections.emptyList();
    }

    @Override
    public AbstractParameters getParameters() {
        return emrServerlessParameters;
    }

    /**
     * Build StartJobRunRequest from parameters and user-provided JSON.
     */
    private StartJobRunRequest buildStartJobRunRequest() {
        String startJobRunRequestJson;
        try {
            startJobRunRequestJson = ParameterUtils.convertParameterPlaceholders(
                    emrServerlessParameters.getStartJobRunRequestJson(),
                    ParameterUtils.convert(taskExecutionContext.getPrepareParamsMap()));
        } catch (Exception e) {
            throw new EmrServerlessTaskException("Failed to resolve parameter placeholders", e);
        }

        StartJobRunRequest request;
        try {
            request = objectMapper.readValue(startJobRunRequestJson, StartJobRunRequest.class);
        } catch (JsonProcessingException e) {
            throw new EmrServerlessTaskException(
                    "Cannot parse StartJobRunRequest from JSON: " + startJobRunRequestJson, e);
        }

        // Override applicationId and executionRoleArn from top-level parameters
        request.setApplicationId(emrServerlessParameters.getApplicationId());
        request.setExecutionRoleArn(emrServerlessParameters.getExecutionRoleArn());

        // Set job name if provided
        if (StringUtils.isNotEmpty(emrServerlessParameters.getJobName())) {
            request.setName(emrServerlessParameters.getJobName());
        } else {

View on GitHub (pinned to 02eac45a1b)