{"record":{"id":"31538022c77ab8d4","repo":"microsoft/aspire","slug":"toolbox-name-changed-concurrently-version-version-was-315380","errorCode":null,"errorMessage":"Toolbox '{name}' changed concurrently: version '{version}' was promoted, but version '{after.DefaultVersion}' is now the default. No further changes were made.","messagePattern":"Toolbox '(.+?)' changed concurrently: version '(.+?)' was promoted, 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":456,"sourceCode":"                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        {\n            throw CreateConcurrentChangeException(\n                definition.Name,\n                $\"version '{version}' was promoted, but version '{after.DefaultVersion}' is now the default\");\n        }\n    }\n\n    private static void ValidateOwnedDefault(\n        string name,\n        FoundryToolboxState state,\n        bool concurrentChange = false)\n    {\n        if (IsAspireManaged(state.Default))\n        {\n            return;\n        }\n\n        if (concurrentChange)\n        {\n            throw CreateConcurrentChangeException(","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReconciler.cs#L438-L474","documentation":"After promoting a Toolbox version, PromoteOwnedVersionAsync verifies that the promoted version actually became the default by re-reading state and comparing after.DefaultVersion to the promoted version. If someone changed the default version concurrently (promoted a different version or reassigned the default), the reconciler throws this error instead of silently accepting a default it did not intend. This keeps Aspire's declared model authoritative over the deployed default.","triggerScenarios":"ReconcileAsync promotes definition version X, then the verification GetAsync shows a different DefaultVersion — caused by another actor promoting/setting a different default between the PromoteVersionAsync call and the verification read.","commonSituations":"Two developers or pipelines deploying different versions of the same Toolbox at once; a manual 'set as default' action in the Foundry portal during a deploy; a scheduled job pinning an older default while CI promotes a newer one.","solutions":["Re-run the deploy so Aspire re-promotes the intended version and the default converges","Find and stop the concurrent actor changing the default (portal action, second pipeline), then re-run","Check the Toolbox's default version in the portal and align your AppHost's declared version with whoever should own it","Serialize deployments per environment (pipeline concurrency group) to prevent competing promotions"],"exampleFix":"// before: concurrent deploys promote different versions\n// pipeline A: version 1.2.0, pipeline B: version 1.3.0\n\n// after: single serialized pipeline promoting the intended version\ncbuilder.AddFoundryToolbox(\"my-toolbox\", version: \"1.3.0\");","handlingStrategy":"retry","validationCode":"// Before deploying, check the current default matches expectations\nvar state = await administration.GetAsync(definition.Name, ct);\nif (state?.DefaultVersion is not null && state.DefaultVersion != definition.Version)\n    logger.LogWarning(\"Default version drift detected: {Default}\", state.DefaultVersion);","typeGuard":null,"tryCatchPattern":"try\n{\n    await reconciler.ReconcileAsync(definition, ct);\n}\ncatch (ConcurrentChangeException)\n{\n    // Someone changed the default concurrently; re-running converges the default.\n    await reconciler.ReconcileAsync(definition, ct);\n}","preventionTips":["Run only one pipeline that promotes Toolbox versions per environment","Avoid manual 'set default' actions in the portal during deployments","Keep the AppHost-declared version as the single source of truth for the default"],"tags":["concurrency","azure","reconciliation","versioning"],"backgroundTag":"concurrent-change-detected","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"}