conductor-oss/conductor · error · IllegalArgumentException

workflowDefinition is a string, but not a valid DSL string

Error message

workflowDefinition is a string, but not a valid DSL string

What it means

SubWorkflowParams.setWorkflowDefinition accepts a String only when it is a DSL expression wrapped in '${...}'. This error fires when the supplied string does not both start with '${' and end with '}' - i.e. it is not a recognized DSL expression. Literal workflow names or raw JSON passed as a string hit this path.

Solutions

  1. If referencing an existing workflow, use the 'name' (and optional 'version') field, not workflowDefinition.
  2. If supplying an inline definition, pass it as a JSON object (LinkedHashMap/WorkflowDef), not a string.
  3. If using a DSL expression, ensure it is wrapped as ${...}.

Example fix

// before: plain string - rejected
{"subWorkflowParam": {"workflowDefinition": "myWorkflow"}}

// after: reference by name instead
{"subWorkflowParam": {"name": "myWorkflow", "version": 1}}
// or inline object:
{"subWorkflowParam": {"workflowDefinition": {"name": "myWorkflow", "version": 1}}}
Defensive patterns

Strategy: validation

Validate before calling

// Validate a DSL string before setting workflowDefinition
static boolean isValidDslString(Object v) {
    return v instanceof String s && s.startsWith("${") && s.endsWith("}");
}
// use the 'name' field for references, or an object for inline defs

Type guard

// Narrow a workflowDefinition value to its valid forms
static boolean isValidWorkflowDefinition(Object v) {
    if (v == null) return true;
    if (v instanceof WorkflowDef) return true;
    if (v instanceof LinkedHashMap) return true;
    return v instanceof String s && s.startsWith("${") && s.endsWith("}");
}

Try / catch

// Catch malformed workflowDefinition and report clearly
try {
    params.setWorkflowDefinition(raw);
} catch (IllegalArgumentException e) {
    throw new BadRequestException(
        "workflowDefinition must be null, a WorkflowDef, an object, or a ${...} DSL string", e);
}

Prevention

When it happens

Trigger: Setting the JSON field 'workflowDefinition' to a plain string that lacks the leading '${' or trailing '}' (e.g. "myWorkflow" or "{\"name\":...}" as a String).

Common situations: Confusing the 'name' field (a registered sub-workflow reference) with 'workflowDefinition'; sending a serialized WorkflowDef JSON as a string instead of an object; passing a non-DSL template string.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/1c537e07a5759c28. Report an issue: GitHub.

Appendix: source

Thrown at common/src/main/java/com/netflix/conductor/common/metadata/workflow/SubWorkflowParams.java:159

    @Deprecated
    @JsonIgnore
    public WorkflowDef getWorkflowDef() {
        return (WorkflowDef) workflowDefinition;
    }

    /**
     * @param workflowDef the workflowDefinition to set
     */
    @JsonSetter("workflowDefinition")
    public void setWorkflowDefinition(Object workflowDef) {
        if (workflowDef == null) {
            this.workflowDefinition = workflowDef;
        } else if (workflowDef instanceof WorkflowDef) {
            this.workflowDefinition = workflowDef;
        } else if (workflowDef instanceof String) {
            if (!(((String) workflowDef).startsWith("${"))
                    || !(((String) workflowDef).endsWith("}"))) {
                throw new IllegalArgumentException(
                        "workflowDefinition is a string, but not a valid DSL string");
            } else {
                this.workflowDefinition = workflowDef;
            }
        } else if (workflowDef instanceof LinkedHashMap) {
            this.workflowDefinition = TaskUtils.convertToWorkflowDef(workflowDef);
        } else {
            throw new IllegalArgumentException(
                    "workflowDefinition must be either null, or WorkflowDef, or a valid DSL string");
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {

View on GitHub (pinned to cf7c3e4a8a)