elsa-workflows/elsa-core · error · BpmnExportUnavailableException

BpmnErrorCodes.ExportNotImported

BpmnErrorCodes.ExportNotImported

Error message

Workflow definition '{definition.DefinitionId}' does not currently carry BPMN source, so it cannot be exported as BPMN 2.0 XML. Either it was never imported from a BPMN document, or a later save replaced its custom properties wholesale and removed the '{SourceXmlCustomPropertyKey}' entry as a side effect of editing something else.

What it means

ResolveSourceXml refuses export with BpmnExportUnavailableException (reason NotImported) when the definition's CustomProperties contain no non-empty SourceXmlCustomPropertyKey. Export requires the original BPMN XML recorded at import time; without it the definition cannot be rendered back to BPMN 2.0 XML. The message distinguishes 'never imported' from a later wholesale custom-properties save that removed the key.

Solutions

  1. Import the workflow from a BPMN document via the BPMN interchange import endpoint so SourceXmlCustomPropertyKey is recorded
  2. If a save dropped the key, re-save the definition through the BPMN import path or restore the custom property containing the source XML
  3. For natively-created definitions, use the appropriate (non-BPMN) export mechanism instead

Example fix

// before
var xml = bpmnService.Export(definitionId); // throws if never imported
// after
var def = await definitions.FindAsync(handle);
if (!def.CustomProperties.ContainsKey(BpmnErrorCodes.SourceXmlCustomPropertyKey))
    await bpmnService.ImportAsync(def.DefinitionId, bpmnDocument);
var xml = bpmnService.Export(def.DefinitionId);
Defensive patterns

Strategy: try-catch

Validate before calling

var imported = definition.CustomProperties.TryGetValue<string>(SourceXmlCustomPropertyKey, out var xml) && !string.IsNullOrEmpty(xml);
if (!imported) throw new InvalidOperationException("Definition has no BPMN source; import first");

Try / catch

try { var xml = service.Export(id); }
catch (BpmnExportUnavailableException ex) when (ex.Reason == BpmnExportUnavailableReason.NotImported) { /* use non-BPMN export or import first */ }

Prevention

When it happens

Trigger: Calling Export on a definition that (a) was created natively and never imported from a BPMN document, or (b) had its CustomProperties overwritten by a save that replaced them wholesale, dropping SourceXmlCustomPropertyKey.

Common situations: Editing the workflow via a generic designer/save API that rewrites custom properties, copying definitions between environments without custom properties, or exporting a definition created from scratch instead of imported.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/a1baf93e8ca1e399. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Bpmn.Interchange/Services/BpmnInterchangeDocumentService.cs:790

    /// <summary>The BPMN <c>calledElement</c> a call activity element carries, kept by the reader for round-trip.</summary>
    private static string? CalledElementOf(BpmnElement element) =>
        element.Properties.TryGetValue(BpmnXmlReader.CalledElementPropertyKey, out var calledElement) ? calledElement : null;

    /// <summary>
    /// The BPMN source a workflow definition was imported from, refusing rather than guessing when it is missing or
    /// no longer trustworthy. See this type's remarks for what "missing" and "stale" mean and why each gets its own
    /// message.
    /// </summary>
    /// <exception cref="BpmnExportUnavailableException">
    /// The definition does not currently carry BPMN source, or it does but the definition has changed since the
    /// source was recorded.
    /// </exception>
    private static string ResolveSourceXml(WorkflowDefinition definition)
    {
        if (!definition.CustomProperties.TryGetValue<string>(SourceXmlCustomPropertyKey, out var xml) || string.IsNullOrEmpty(xml))
        {
            throw new BpmnExportUnavailableException(
                $"Workflow definition '{definition.DefinitionId}' does not currently carry BPMN source, so it cannot be exported as BPMN 2.0 XML. "
                + "Either it was never imported from a BPMN document, or a later save replaced its custom properties wholesale and removed the "
                + $"'{SourceXmlCustomPropertyKey}' entry as a side effect of editing something else.",
                BpmnExportUnavailableReason.NotImported);
        }

        if (!definition.CustomProperties.TryGetValue<int>(SourceVersionCustomPropertyKey, out var sourceVersion))
        {
            // Distinct from both other refusals: this is not "never imported" (the source text is right there) and
            // not "stale" (there is no version to compare against yet). ImportAsync writes SourceXmlCustomPropertyKey
            // and SourceVersionCustomPropertyKey together, in the single save described in its remarks, so this path
            // is not reachable through import itself; it is kept as a defence against the same combination arising
            // some other way — e.g. custom properties edited or migrated directly, outside ImportAsync — where
            // "whether the source still matches" cannot be verified without a version to compare against.
            throw new BpmnExportUnavailableException(
                $"Workflow definition '{definition.DefinitionId}' carries BPMN source, but not the definition version it was recorded against, so "
                + "whether that source still matches this definition cannot be verified. It does not mean this definition was never imported from "
                + "BPMN, and it does not mean the source is stale — there is simply no version recorded to compare against. Re-import the document to "

View on GitHub (pinned to fe9217bdfa)