microsoft/aspire · error · InvalidOperationException

Toolbox ' ' changed concurrently: version ' ' was created…

Error message

Toolbox '{name}' changed concurrently: version '{version}' was created or selected, but the Toolbox is no longer visible. No further changes were made.

What it means

Before promoting a Toolbox version to default, the reconciler re-reads the Toolbox (Foundry Toolbox administration has no ETag/conditional update) and requires it to still exist and match the reconciled state. This error means the version was created or selected successfully, but the Toolbox vanished before promotion - a concurrent writer deleted it. The reconciler made no further changes to avoid clobbering other deployments.

Solutions

  1. Re-run the deployment - it will recreate the Toolbox and retry promotion.
  2. Ensure only one deployment mutates the same Foundry project at a time.
  3. Investigate portal audit logs for the deleting actor.
  4. Isolate environments to separate Foundry projects/Toolbox names.
Defensive patterns

Strategy: retry

Try / catch

try
{
    await deploy.RunAsync();
}
catch (Exception ex) when (ex.Message.Contains("no longer visible"))
{
    logger.LogWarning(ex, "Toolbox deleted concurrently; retrying deployment.");
    await deploy.RunAsync();
}

Prevention

When it happens

Trigger: PromoteOwnedVersionAsync calls administration.GetAsync(definition.Name) and receives null; ReconcileAsync throws the concurrent-change error via CreateConcurrentChangeException.

Common situations: Concurrent deployments where one deletes/recreates the Toolbox; manual portal deletion during a deploy; retention/cleanup policies removing the Toolbox mid-deployment.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/1e933b613cb825cb. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReconciler.cs:420

            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(
                definition.Name,
                $"version '{version}' was created or selected, but the Toolbox is no longer visible");

        ValidateOwnedDefault(definition.Name, before, concurrentChange: true);
        ValidatePromotionTarget(definition, before, version);
        if (string.Equals(before.DefaultVersion, version, StringComparison.Ordinal))
        {
            return;
        }

        if (observedDefaultVersion is null ||
            !string.Equals(before.DefaultVersion, observedDefaultVersion, StringComparison.Ordinal))
        {
            var expectedDefault = observedDefaultVersion is null
                ? "no default version"
                : $"default version '{observedDefaultVersion}'";
            throw CreateConcurrentChangeException(
                definition.Name,

View on GitHub (pinned to 25830f84bd)