elsa-workflows/elsa-core · error · ObjectDisposedException

IWorkflowCommitNotificationScope

Error message

IWorkflowCommitNotificationScope

What it means

The scope object implementing IWorkflowCommitNotificationScope guards against use after disposal. ThrowIfDisposed throws ObjectDisposedException(nameof(IWorkflowCommitNotificationScope)) when any member is accessed after the scope was disposed (e.g. after the workflow commit completed).

Solutions

  1. Ensure all notification enqueueing happens within the scope's lifetime (before Dispose / before the workflow completes).
  2. Do not capture the scope in background tasks; capture the data and enqueue synchronously during the commit.
  3. Check _disposed (IsDisposed) before using the scope if lifetime is uncertain.
  4. Restructure so the scope follows the using/RAII pattern tightly around the code that needs it.

Example fix

// before
_scope = notificationScope; // stored in field, used after commit

// after
using var scope = await factory.BeginScopeAsync(ct);
scope.Enqueue(notification, strategy);
// scope disposed here; never used afterwards
Defensive patterns

Strategy: try-catch

Validate before calling

if (scope is IDisposable d && /* track disposed flag */ false) { /* check before use */ }

Type guard

bool ScopeUsable(IWorkflowCommitNotificationScope scope) => scope is not { } disposedScope || !IsDisposed(disposedScope); // prefer storing your own _disposed flag

Try / catch

try
{
    scope.Enqueue(notification, strategy);
}
catch (ObjectDisposedException)
{
    logger.LogWarning("Commit notification scope already disposed; notification dropped.");
}

Prevention

When it happens

Trigger: Holding a reference to an IWorkflowCommitNotificationScope (obtained via BeginScope-like APIs) and calling methods on it after Dispose, such as enqueueing notifications from a background task that outlives the workflow execution.

Common situations: Fire-and-forget tasks capturing the scope and writing notifications after the workflow finished; using a scope stored in a long-lived field; accidentally disposing the scope in a using block while still enqueuing afterwards.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/modules/Elsa.Workflows.Runtime/Services/WorkflowCommitNotificationBuffer.cs:85

            if (exceptions is { Count: > 0 })
                throw new AggregateException("One or more workflow commit notifications failed.", exceptions);
        }

        public void Dispose()
        {
            if (_disposed)
                return;

            _disposed = true;
            if (ReferenceEquals(owner._currentScope.Value, this))
                owner._currentScope.Value = parent;
        }

        private void ThrowIfDisposed()
        {
            if (_disposed)
                throw new ObjectDisposedException(nameof(IWorkflowCommitNotificationScope));
        }
    }

    private record Entry(INotification Notification, IEventPublishingStrategy? Strategy);
}

View on GitHub (pinned to fe9217bdfa)