OrchardCMS/OrchardCore · error · OpenIddictExceptions.ConcurrencyException

The authorization was concurrently updated and cannot be…

Error message

The authorization was concurrently updated and cannot be persisted in its current state.
Reload the authorization from the database and retry the operation.

What it means

OpenIdAuthorizationStore.UpdateAsync flushes the session to persist an OpenIddict authorization document. A YesSql ConcurrencyException (another writer updated the same authorization) is caught and rethrown as OpenIddictExceptions.ConcurrencyException per the OpenIddict contract.

Solutions

  1. Reload the authorization from the database and retry the update.
  2. Make authorization updates idempotent and retry transient concurrency conflicts.
  3. Avoid concurrent writes to the same authorization by serializing refresh/redemption flows per grant.
  4. Check for duplicated background jobs (e.g. cleanup workers) touching the same authorizations.

Example fix

// before
await store.UpdateAsync(authorization, cancellationToken);
// after
try
{
    await store.UpdateAsync(authorization, cancellationToken);
}
catch (OpenIddictExceptions.ConcurrencyException)
{
    var fresh = await store.FindAsync(authorization.Id, cancellationToken);
    // re-apply changes to 'fresh' and retry
}
Defensive patterns

Strategy: retry

Try / catch

try
{
    await store.UpdateAsync(authorization, ct);
}
catch (OpenIddictExceptions.ConcurrencyException)
{
    var fresh = await store.FindAsync(authorization.Id, ct);
    // merge/re-apply changes and retry once
}

Prevention

When it happens

Trigger: Concurrent token/authorization flows updating the same authorization row (e.g. two refresh-token requests for the same grant, or parallel background cleanup and token redemption).

Common situations: Refresh-token storms from multiple devices/clients using the same authorization; duplicate scheduled tasks revoking or updating authorizations; race between logout (revocation) and token refresh.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/beb17857e6b6a1cc. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore/OrchardCore.OpenId.Core/YesSql/Stores/OpenIdAuthorizationStore.cs:573

        return default;
    }

    /// <inheritdoc/>
    public virtual async ValueTask UpdateAsync(TAuthorization authorization, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(authorization);

        cancellationToken.ThrowIfCancellationRequested();

        await _session.SaveAsync(authorization, checkConcurrency: true, collection: OpenIdCollection, cancellationToken: cancellationToken);

        try
        {
            await _session.FlushAsync(cancellationToken);
        }
        catch (ConcurrencyException exception)
        {
            throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder()
                .AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")
                .Append("Reload the authorization from the database and retry the operation.")
                .ToString(), exception);
        }
    }
}

View on GitHub (pinned to 4306c0717f)