flowable/flowable-engine · error · ActivitiIllegalArgumentException

invalid: multiple sources

Error message

invalid: multiple sources ${this.streamSource} and ${streamSource}

What it means

A single BpmnParse instance can only have one input source. setStreamSource throws ActivitiIllegalArgumentException if a source (stream, string, resource, or URL) was already set on this parser instance, to prevent ambiguous input.

Solutions

  1. Create a fresh BpmnParse instance (via processEngineConfiguration.getBpmnParser().createParse()) for each source you parse
  2. Remove the duplicate source-setting call so exactly one source is configured per parse
  3. If parsing many resources, loop and build a new parse per iteration instead of reusing the object

Example fix

// before (reuse)
BpmnParse parse = parser.createParse().sourceResource(a);
parse.sourceString(xml); // throws
// after
BpmnParse parse = parser.createParse().sourceResource(a);
BpmnParse parse2 = parser.createParse().sourceString(xml);
Defensive patterns

Strategy: type-guard

Validate before calling

// guard before reuse
if (parse != null && alreadyConfigured) {
  parse = processEngineConfiguration.getBpmnParser().createParse();
}

Type guard

static boolean canSetSource(BpmnParse parse) {
  return parse != null; // treat one parse per source: never set two sources
}

Try / catch

try {
  parse.sourceString(xml);
} catch (ActivitiIllegalArgumentException e) {
  if (e.getMessage().startsWith("invalid: multiple sources")) {
    parse = parser.createParse().sourceString(xml); // fresh parse
  }
}

Prevention

When it happens

Trigger: Calling setStreamSource (directly or via sourceString/sourceInputStream/sourceResource/sourceUrl) twice on the same BpmnParse object.

Common situations: Reusing a BpmnParse/parse helper object across multiple deployments in a loop; chaining two source-setting calls by mistake; copy-pasted parse setup code that sets both a resource and a string.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/44dcab765ae5d370. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/parser/BpmnParse.java:274

    public BpmnParse sourceResource(String resource, ClassLoader classLoader) {
        if (name == null) {
            name(resource);
        }
        setStreamSource(new ResourceStreamSource(resource, classLoader));
        return this;
    }

    public BpmnParse sourceString(String string) {
        if (name == null) {
            name("string");
        }
        setStreamSource(new StringStreamSource(string));
        return this;
    }

    protected void setStreamSource(StreamSource streamSource) {
        if (this.streamSource != null) {
            throw new ActivitiIllegalArgumentException("invalid: multiple sources " + this.streamSource + " and " + streamSource);
        }
        this.streamSource = streamSource;
    }

    /**
     * Parses the 'definitions' root element
     */
    protected void transformProcessDefinitions() {
        sequenceFlows = new HashMap<>();
        for (Process process : bpmnModel.getProcesses()) {
            if (process.isExecutable()) {
                bpmnParserHandlers.parseElement(this, process);
            }
        }

        if (!processDefinitions.isEmpty()) {
            processDI();
        }

View on GitHub (pinned to d6d39ce1c6)