microsoft/aspire · error · InvalidOperationException
Toolbox ' ' changed concurrently: default version ' '…
Error message
Toolbox '{name}' changed concurrently: default version '{expectedDefaultVersion}' matched, but version '{current.DefaultVersion}' with a different configuration is now the default. No further changes were made. What it means
The Foundry Toolbox reconciler verifies, immediately before reusing an existing default, that the default version and its configuration hash are unchanged since reconciliation (Foundry Toolbox administration lacks conditional updates). This error means another writer switched the Toolbox default to a different version with different configuration between the reconciler's read and its action; the reconciler aborts without changes to avoid overwriting another deployment's newer default.
Solutions
- Re-run the deployment so the reconciler observes and promotes the intended version freshly.
- Serialize deployments to the same Foundry project (avoid concurrent envs/branches).
- Align Toolbox configuration across pipelines, or give each pipeline its own Toolbox name/project.
- Compare the reported current.DefaultVersion with the expected version to identify which deployment won.
Defensive patterns
Strategy: retry
Try / catch
try
{
await deploy.RunAsync();
}
catch (Exception ex) when (ex.Message.Contains("with a different configuration is now the default"))
{
logger.LogWarning(ex, "Another deployment changed the Toolbox default; retrying.");
await deploy.RunAsync();
} Prevention
- Ensure all pipelines deploy identical Toolbox configuration, or isolate per-environment Toolboxes.
- Serialize deployments to the same Foundry project.
- Don't promote default versions manually in the portal during deploys.
When it happens
Trigger: VerifyReusedDefaultAsync finds current.DefaultVersion != expectedDefaultVersion (ordinal compare), or current.Default.Metadata lacks ConfigurationHashMetadataKey or its hash differs from definition.ConfigurationHash; ReconcileAsync throws the concurrent-change error.
Common situations: Two pipelines deploying different Toolbox configurations to the same project; manual default-version promotion in the portal during deploy; a stale deployment re-run against a Toolbox already updated by a newer deployment.
Related errors
- Toolbox ' ' changed concurrently: default version ' '…
- Toolbox ' ' changed concurrently: expected , but version '…
- Toolbox ' ' changed concurrently: version ' ' was created…
- Project ' ' does not have a valid connection string.
- Project ' ' does not have a valid endpoint.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/6b07633b6be33121.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReconciler.cs:402
private async Task VerifyReusedDefaultAsync(
FoundryToolboxDeploymentDefinition definition,
string expectedDefaultVersion,
CancellationToken cancellationToken)
{
var current = await administration.GetAsync(definition.Name, cancellationToken).ConfigureAwait(false)
?? throw CreateConcurrentChangeException(
definition.Name,
$"default version '{expectedDefaultVersion}' matched, but the Toolbox is no longer visible");
ValidateOwnedDefault(definition.Name, current, concurrentChange: true);
if (!string.Equals(current.DefaultVersion, expectedDefaultVersion, StringComparison.Ordinal) ||
!current.Default.Metadata.TryGetValue(
FoundryToolboxDeploymentDefinition.ConfigurationHashMetadataKey,
out var currentHash) ||
!string.Equals(currentHash, definition.ConfigurationHash, StringComparison.Ordinal))
{
throw CreateConcurrentChangeException(
definition.Name,
$"default version '{expectedDefaultVersion}' matched, but version '{current.DefaultVersion}' with a different configuration is now the default");
}
}
private async Task PromoteOwnedVersionAsync(
FoundryToolboxDeploymentDefinition definition,
string version,
string? observedDefaultVersion,
CancellationToken cancellationToken)
{
// Toolbox administration has no conditional update or ETag support. Re-read immediately
// before promotion and require the exact default observed while reconciling. Otherwise one
// Aspire deployment could overwrite another Aspire deployment's newer default. This is
// coordination, not an atomic lock: another writer can still update the Toolbox after the
// final read.
var before = await administration.GetAsync(definition.Name, cancellationToken).ConfigureAwait(false)
?? throw CreateConcurrentChangeException(View on GitHub (pinned to 25830f84bd)