{"record":{"id":"56c6615dc73d7503","repo":"microsoft/aspire","slug":"toolbox-name-changed-concurrently-default-version","errorCode":null,"errorMessage":"Toolbox '{name}' changed concurrently: default version '{expectedDefaultVersion}' matched, but the Toolbox is no longer visible. No further changes were made.","messagePattern":"Toolbox '(.+?)' changed concurrently: default version '(.+?)' matched, but the Toolbox is no longer visible\\. No further changes were made\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReconciler.cs","lineNumber":391,"sourceCode":"        if (!string.Equals(existing.DefaultVersion, updated, StringComparison.Ordinal))\n        {\n            await PromoteOwnedVersionAsync(\n                definition,\n                updated,\n                existing.DefaultVersion,\n                cancellationToken).ConfigureAwait(false);\n        }\n\n        return new(updated, FoundryToolboxReconcileAction.CreatedAndPromoted);\n    }\n\n    private async Task VerifyReusedDefaultAsync(\n        FoundryToolboxDeploymentDefinition definition,\n        string expectedDefaultVersion,\n        CancellationToken cancellationToken)\n    {\n        var current = await administration.GetAsync(definition.Name, cancellationToken).ConfigureAwait(false)\n            ?? throw CreateConcurrentChangeException(\n                definition.Name,\n                $\"default version '{expectedDefaultVersion}' matched, but the Toolbox is no longer visible\");\n\n        ValidateOwnedDefault(definition.Name, current, concurrentChange: true);\n        if (!string.Equals(current.DefaultVersion, expectedDefaultVersion, StringComparison.Ordinal) ||\n            !current.Default.Metadata.TryGetValue(\n                FoundryToolboxDeploymentDefinition.ConfigurationHashMetadataKey,\n                out var currentHash) ||\n            !string.Equals(currentHash, definition.ConfigurationHash, StringComparison.Ordinal))\n        {\n            throw CreateConcurrentChangeException(\n                definition.Name,\n                $\"default version '{expectedDefaultVersion}' matched, but version '{current.DefaultVersion}' with a different configuration is now the default\");\n        }\n    }\n\n    private async Task PromoteOwnedVersionAsync(\n        FoundryToolboxDeploymentDefinition definition,","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReconciler.cs#L373-L409","documentation":"Foundry Toolbox administration has no conditional update/ETag support, so the reconciler re-reads the Toolbox immediately before reusing its default version and verifies it still matches the state observed during reconciliation. This error means the expected default version matched, but the Toolbox disappeared before the reconciler could act - a concurrent writer deleted it. No further changes were made, keeping the deployment safe.","triggerScenarios":"VerifyReusedDefaultAsync calls administration.GetAsync(definition.Name) and gets null after the default version was observed to match; ReconcileAsync converts this into a concurrent-change error via CreateConcurrentChangeException.","commonSituations":"Two Aspire deployments/CI pipelines targeting the same Foundry project simultaneously, one deleting/recreating the Toolbox; manual deletion in the Azure portal during a deploy; cleanup scripts racing with deploy.","solutions":["Re-run the deployment - the reconciler is idempotent and will recreate the Toolbox.","Serialize deployments to the same Foundry project/Toolbox (one at a time).","Check the Azure portal/audit logs for who deleted the Toolbox mid-deployment.","Use distinct Foundry projects or Toolbox names per environment/branch."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight: confirm the Toolbox exists and matches expectations before deploying\nvar toolbox = await administration.GetAsync(toolboxName);\nif (toolbox is null)\n    throw new InvalidOperationException($\"Toolbox '{toolboxName}' is missing; another writer may have deleted it.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    await deploy.RunAsync();\n}\ncatch (Exception ex) when (ex.Message.Contains(\"changed concurrently\"))\n{\n    logger.LogWarning(ex, \"Concurrent Toolbox change detected; retrying deployment once.\");\n    await deploy.RunAsync(); // reconciler is idempotent\n}","preventionTips":["Use CI concurrency groups so only one deployment targets a Foundry project at a time.","Avoid manual portal edits to Toolboxes during deployments.","Give each environment/branch its own Toolbox name or Foundry project."],"tags":["azure","foundry","toolbox","concurrency","deployment"],"backgroundTag":"concurrent-modification","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}