elsa-workflows/elsa-core · error · InvalidOperationException

Runtime entity definition

Error message

Runtime entity definition '{definition.Name}' is not published.

What it means

SaveInstanceAsync requires the referenced definition to be in Published status; Draft or Retired definitions reject writes. When the definition exists but its Status differs from Published, the manager throws InvalidOperationException naming the definition.

Solutions

  1. Call PublishAsync(definitionName) to move the definition to Published before saving instances.
  2. If the definition was retired, publish a new version and update writers to use it.
  3. Check definition.Status via GetDefinitionAsync in orchestration code and skip/park instance writes while not Published.

Example fix

// before
await manager.SaveDraftAsync(definition);
await manager.SaveInstanceAsync(instance); // throws: not published
// after
await manager.SaveDraftAsync(definition);
await manager.PublishAsync(definition.Name);
await manager.SaveInstanceAsync(instance);
Defensive patterns

Strategy: validation

Validate before calling

var def = await manager.GetDefinitionAsync(instance.DefinitionName);
if (def is not null && def.Status != RuntimeEntityDefinitionStatus.Published)
    throw new InvalidOperationException($"Definition '{def.Name}' must be Published before saving instances.");

Try / catch

try { await manager.SaveInstanceAsync(instance); }
catch (InvalidOperationException ex) when (ex.Message.Contains("is not published")) { /* publish definition or queue the write */ }

Prevention

When it happens

Trigger: Saving an instance while the definition is still Draft (SaveDraftAsync without PublishAsync), or after RetireAsync was called for the definition.

Common situations: Forgetting the publish step after editing a definition; retiring an old definition while background jobs still write instances; seeding data against a freshly created draft in tests.

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 elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/2552314d6b5ec2ea. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Persistence.VNext.Runtime/Services/RuntimeEntityManager.cs:73

        var existing = await LoadDefinitionDocumentAsync(name, cancellationToken)
            ?? throw new InvalidOperationException($"Runtime entity definition '{name}' was not found.");

        existing.Definition.Status = RuntimeEntityDefinitionStatus.Retired;
        existing.Definition.UpdatedAt = DateTimeOffset.UtcNow;

        await SaveDefinitionAsync(existing.Definition, existing.Document.Version, cancellationToken);
        await AppendAuditAsync("RuntimeEntityDefinition", existing.Definition.Name, "Retired", $"Version {existing.Definition.Version} retired.", cancellationToken);
        return existing.Definition;
    }

    public async Task<RuntimeEntityInstance> SaveInstanceAsync(RuntimeEntityInstance instance, CancellationToken cancellationToken = default)
    {
        instance.DefinitionName = NormalizeName(instance.DefinitionName);
        var definition = await GetDefinitionAsync(instance.DefinitionName, cancellationToken)
            ?? throw new InvalidOperationException($"Runtime entity definition '{instance.DefinitionName}' was not found.");

        if (definition.Status != RuntimeEntityDefinitionStatus.Published)
            throw new InvalidOperationException($"Runtime entity definition '{definition.Name}' is not published.");

        validator.ValidateInstance(definition, instance);
        instance.DefinitionVersion = definition.Version;

        var existing = await LoadInstanceDocumentAsync(instance.DefinitionName, instance.Id, cancellationToken);
        var now = DateTimeOffset.UtcNow;
        instance.CreatedAt = existing?.Instance.CreatedAt ?? instance.CreatedAt;
        instance.UpdatedAt = now;

        var request = new SaveDocumentRequest(
            RuntimeEntityPersistenceSchemaProvider.InstancesStorageUnit,
            CreateInstanceDocumentId(instance.DefinitionName, instance.Id),
            JsonSerializer.Serialize(instance, _jsonOptions),
            CreateInstanceIndexValues(definition, instance),
            existing?.Document.Version ?? 0);

        await documentStore.SaveAsync(request, cancellationToken);
        await AppendAuditAsync("RuntimeEntityInstance", CreateInstanceDocumentId(instance.DefinitionName, instance.Id), existing is null ? "Created" : "Updated", null, cancellationToken);

View on GitHub (pinned to fe9217bdfa)