OrchardCMS/OrchardCore · error · TimeoutException
Couldn't acquire a lock to update the sitemap within
Error message
Couldn't acquire a lock to update the sitemap within {timeout.Seconds} seconds. What it means
DefaultSitemapUpdateHandler.TryUpdateSitemapAsync acquires a distributed lock (SITEMAPS_UPDATE_LOCK) with a 20-second timeout before rebuilding sitemaps. If the lock cannot be acquired within that window — because another sitemap update is still running — it throws TimeoutException to prevent concurrent/overlapping sitemap rebuilds.
Solutions
- Reduce sitemap size/complexity (page via sitemap index, limit entries) so rebuilds finish under 20 seconds.
- Retry the update after a delay — the error means the lock was busy, so re-trigger the sitemap rebuild.
- Ensure only one node/rebuild process updates sitemaps at a time (stagger background tasks, avoid simultaneous saves).
- Check whether another process is stuck holding the lock (hanging rebuild) and restart it; investigate slow sitemap builders.
Example fix
// before (caller)
await _sitemapManager.TryUpdateSitemapAsync(sitemapId);
// after (caller with retry)
try { await _sitemapManager.TryUpdateSitemapAsync(sitemapId); }
catch (TimeoutException) { _logger.LogWarning("Sitemap update locked; will retry."); await Task.Delay(5000); /* retry */ } Defensive patterns
Strategy: retry
Validate before calling
// no pre-call validation possible; check lock contention before retrying
var recent = await _distributedLockService.TryAcquireLockAsync("SITEMAPS_UPDATE_LOCK", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
if (!recent.locked) logger.LogWarning("Sitemap update lock is currently held; defer the rebuild."); Try / catch
try {
await sitemapManager.TryUpdateSitemapAsync(sitemapId);
} catch (TimeoutException ex) when (ex.Message.Contains("sitemap")) {
await Task.Delay(TimeSpan.FromSeconds(30));
// retry once, or enqueue a background rebuild
} Prevention
- Debounce sitemap rebuilds triggered by rapid content/sitemap saves.
- Use sitemap index + caching to keep rebuilds under 20 seconds.
- Stagger sitemap rebuilds across nodes in multi-server farms.
- Run large rebuilds in a background task with retry.
When it happens
Trigger: Two or more sitemap update requests overlap (e.g. saving a sitemap while a scheduled/background rebuild holds the lock for more than 20 seconds); large sitemap generation exceeding the lock timeout; multi-node farms contending for the lock.
Common situations: Multi-server Orchard deployments with a shared distributed lock; very large sitemaps (tens of thousands of URLs) taking longer than 20s to build; rapid successive saves to sitemap entries triggering rebuilds.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Failed to acquire a lock before activating the tenant
- Fails to acquire an auto setup lock for the tenant
- Unable to reload the tenant
- Can't resolve a scope on tenant
- The ' ' could not be persisted and cached as it has been…
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/422fb8f24db477bb.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore.Modules/OrchardCore.Sitemaps/Handlers/DefaultSitemapUpdateHandler.cs:28
public DefaultSitemapUpdateHandler(
IEnumerable<ISitemapTypeUpdateHandler> sitemapTypeUpdateHandlers,
IDistributedLock distributedLock)
{
_sitemapTypeUpdateHandlers = sitemapTypeUpdateHandlers;
_distributedLock = distributedLock;
}
public async Task UpdateSitemapAsync(SitemapUpdateContext context)
{
// Doing the update in a synchronized way makes sure that two simultaneous content item updates don't cause
// a ConcurrencyException due to the same sitemap document being updated.
var timeout = TimeSpan.FromMilliseconds(20_000);
(var locker, var locked) = await _distributedLock.TryAcquireLockAsync("SITEMAPS_UPDATE_LOCK", timeout, timeout);
if (!locked)
{
throw new TimeoutException($"Couldn't acquire a lock to update the sitemap within {timeout.Seconds} seconds.");
}
using (locker)
{
foreach (var sitemapTypeUpdateHandler in _sitemapTypeUpdateHandlers)
{
await sitemapTypeUpdateHandler.UpdateSitemapAsync(context);
}
}
}
}
View on GitHub (pinned to 4306c0717f)