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
- Reload the authorization from the database and retry the update.
- Make authorization updates idempotent and retry transient concurrency conflicts.
- Avoid concurrent writes to the same authorization by serializing refresh/redemption flows per grant.
- 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
- Make token refresh/redemption flows idempotent per authorization.
- Limit concurrent refresh requests per grant (single-use refresh tokens).
- Ensure only one cleanup/revocation worker runs per instance.
- Apply bounded retry-with-reload on concurrency conflicts.
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
- The application was concurrently updated and cannot be…
- The scope was concurrently updated and cannot be persisted…
- The token was concurrently updated and cannot be persisted…
- Unable to reload the tenant
- Can't resolve a scope on tenant
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)