{"record":{"id":"8b87bf9b210bee6b","repo":"microsoft/aspire","slug":"toolbox-name-changed-concurrently-expected-expecteddefault","errorCode":null,"errorMessage":"Toolbox '{name}' changed concurrently: expected {expectedDefault}, but version '{before.DefaultVersion}' is now the default. No further changes were made.","messagePattern":"Toolbox '(.+?)' changed concurrently: expected (.+?), but version '(.+?)' is now the default\\. No further changes were made\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReconciler.cs","lineNumber":437,"sourceCode":"        var before = await administration.GetAsync(definition.Name, cancellationToken).ConfigureAwait(false)\n            ?? throw CreateConcurrentChangeException(\n                definition.Name,\n                $\"version '{version}' was created or selected, but the Toolbox is no longer visible\");\n\n        ValidateOwnedDefault(definition.Name, before, concurrentChange: true);\n        ValidatePromotionTarget(definition, before, version);\n        if (string.Equals(before.DefaultVersion, version, StringComparison.Ordinal))\n        {\n            return;\n        }\n\n        if (observedDefaultVersion is null ||\n            !string.Equals(before.DefaultVersion, observedDefaultVersion, StringComparison.Ordinal))\n        {\n            var expectedDefault = observedDefaultVersion is null\n                ? \"no default version\"\n                : $\"default version '{observedDefaultVersion}'\";\n            throw CreateConcurrentChangeException(\n                definition.Name,\n                $\"expected {expectedDefault}, but version '{before.DefaultVersion}' is now the default\");\n        }\n\n        await administration.PromoteVersionAsync(\n            definition.Name,\n            version,\n            cancellationToken).ConfigureAwait(false);\n\n        var after = await administration.GetAsync(definition.Name, cancellationToken).ConfigureAwait(false)\n            ?? throw CreateConcurrentChangeException(\n                definition.Name,\n                \"the Toolbox was no longer visible after promotion\");\n\n        ValidateOwnedDefault(definition.Name, after, concurrentChange: true);\n        ValidatePromotionTarget(definition, after, version);\n        if (!string.Equals(after.DefaultVersion, version, StringComparison.Ordinal))\n        {","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReconciler.cs#L419-L455","documentation":"The reconciler records the Toolbox's default version observed during reconciliation and re-checks it right before promoting the owned version, because Foundry Toolbox administration lacks conditional updates. This error means the default changed between the check and the promotion (or a default exists where none was observed), so the reconciler aborts without changes to avoid overwriting another deployment's newer default.","triggerScenarios":"PromoteOwnedVersionAsync reads 'before', then finds before.DefaultVersion does not equal observedDefaultVersion (ordinal), or observedDefaultVersion is null while a default now exists; ReconcileAsync throws the concurrent-change error.","commonSituations":"Two Aspire deployments promoting different versions to the same Toolbox; manual default promotion in the Azure portal during a deploy; a retry of an old deployment racing a newer successful one.","solutions":["Re-run the deployment so it observes the current default and re-promotes deterministically.","Serialize deployments against the same Foundry project (CI concurrency groups, locks).","Use separate Toolbox names or Foundry projects per environment/branch.","Verify which deployment changed the default via audit logs and align configurations."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    await deploy.RunAsync();\n}\ncatch (Exception ex) when (ex.Message.Contains(\"is now the default\"))\n{\n    logger.LogWarning(ex, \"Toolbox default changed concurrently; retrying deployment.\");\n    await deploy.RunAsync();\n}","preventionTips":["Serialize deployments (locks/concurrency groups) so promotions don't race.","Use separate Toolbox names or Foundry projects per environment.","Re-run stale deployments rather than layering them over newer successful ones."],"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"}