Repository navigation
Description
aspire restore silently runs the previous CLI version's TypeScript code generator after a version switch
Summary
aspire restore rewrites the generated IntegrationRestore.csproj with the current CLI's package version, but does not re-restore or rebuild it. The previously built generator assembly stays in bin/, so code generation runs with the old CLI's generator while reporting success. Any codegen fix in a newer CLI silently does not apply until the user deletes .aspire/ by hand.
Repro
A TypeScript AppHost. Two CLI versions installed — released 13.5.1 and a dogfood build 13.6.0-pr.19577.gfa0aea2c (which contains the #19577 codegen fix).
# 1. clean generate with the newer CLI -> correct output
rm -rf .aspire && aspire-13.6.0-pr restore
# 2. generate with the older CLI -> old (buggy) output, as expected
aspire-13.5.1 restore
# 3. generate with the newer CLI again -> STILL the old buggy output
aspire-13.6.0-pr restoreStep 3 prints ✅ SDK code restored successfully with no warning.
Observed state after step 3
| What | Value |
|---|---|
integration-restore/IntegrationRestore.csproj PackageReference |
13.6.0-pr.19577.gfa0aea2c ✅ rewritten |
RestoreAdditionalProjectSources |
points at the new hive ✅ |
integration-restore/obj/project.assets.json |
Aspire.Hosting.CodeGeneration.TypeScript/13.5.1 ❌ |
integration-restore/bin/Debug/net10.0/Aspire.Hosting.CodeGeneration.TypeScript.dll |
13.5.1+69db530a… ❌ |
generated .aspire/modules/aspire.mts |
old generator's output ❌ |
| exit / message | success, no warning ❌ |
File mtimes show the ordering:
09:57:36 IntegrationRestore.csproj <- rewritten to 13.6.0-pr
09:57:19 obj/project.assets.json <- 17s EARLIER, still 13.5.1
07:54:51 obj/aspire-restore.stamp <- hours old, never refreshed
2026-08-20 19:03 bin/.../CodeGeneration.TypeScript.dll <- 13.5.1 package content
obj/aspire-restore.stamp never being refreshed looks like the gate: the CLI decides the integration restore is up to date and skips it, despite having just written a csproj that pins a different package version. .codegen-hash does change, so code generation itself re-runs — it just runs the stale generator.
The new package is present and resolvable (~/.aspire/hives/pr-19577/packages/Aspire.Hosting.CodeGeneration.TypeScript.13.6.0-pr.19577.gfa0aea2c.nupkg), so this is not a resolution failure.
Asymmetry
Going down (13.6.0-pr → 13.5.1) does rebuild correctly — csproj, project.assets.json, and bin/ all move to 13.5.1. Only the second switch fails to rebuild, which is what makes it easy to miss.
Why it matters
The failure mode is invisible and actively misleading. Verifying a codegen fix by installing a PR build and re-running aspire restore reports success and produces the unfixed output — which reads as "the fix does not work." It cost me a false negative while validating #19577 against the sample from #19507.
Deleting .aspire/modules is not sufficient — codegen re-runs against the stale generator in .aspire/integrations/. Only rm -rf .aspire works.
Suggestions
- Include the CLI / codegen package version in whatever
obj/aspire-restore.stampgates on, so a version change forces re-restore and rebuild. - Or compare the resolved version in
project.assets.jsonagainst the version just written to the csproj, and re-restore on mismatch. - At minimum, warn when the built generator assembly's version differs from the running CLI's, instead of reporting plain success.
Environment
- Aspire CLI
13.5.1+69db530a4816698cf1d5fa4557933e0ac4f127c6and13.6.0-pr.19577.gfa0aea2c - linux-x64 (WSL2), .NET SDK with net10.0 target
- Dogfood build installed via
eng/scripts/get-aspire-cli-pr.sh 19577
Related
- Fix TypeScript codegen dropping Promise wrapper for zero-capability resource builders #19577 / TypeScript AppHost codegen omits *Promise/*PromiseImpl wrapper for exports returning a bare Aspire interface #19507 — the codegen fix whose verification this masked.
- CLI 13.4.6 fails TypeScript code generation with SDK 13.5 due to frozen TypeSystem contract #19503 — also a CLI/codegen version-skew failure, but a different root cause (frozen
Aspire.TypeSystemcontract producingMissingMethodExceptionat bind time). This one is a build-staleness problem inintegration-restore, and fails silently rather than throwing.
Activity
Sharpen the stale-codegen caveat and link the upstream issue
flojon commentedon Aug 22, 2026
Correcting the scope of my own report — the title generalizes too far. Follow-up testing with a third CLI (released 13.5.2) narrows it considerably.
I could not reproduce this between two released versions. It only reproduces when returning to a PR/dogfood build whose package comes from a local hive folder source.
Each run below is
aspire restoreon the same TypeScript AppHost, recording the pinned version in the generatedIntegrationRestore.csproj, the version NuGet actually resolved inobj/project.assets.json, and the version of the generator assembly inbin/:bin/dllMinimal deterministic repro, confirmed twice:
So two conditions both appear necessary: the target version must be a hive-sourced PR build, and it must have been built in that directory before. A first-time switch to the dogfood build works correctly, which is why the plain A → B case never showed it.
The mtimes in the failing run point at ordering rather than a stamp:
Restore ran against the csproj as it stood before the rewrite, and nothing re-restored afterwards.
RestoreAdditionalProjectSourcesdoes end up correct in the final csproj (the hive path is present), so the hive is reachable — it just wasn't in the csproj that restore actually consumed.Practical impact is therefore narrower than I first wrote, but lands squarely on PR validation: install a dogfood build, compare against a release, go back to the dogfood build, and you silently get the release's generator while
restorereports success. That is exactly the loop someone runs to verify a codegen fix. Everything else in the report stands — deleting.aspire/modulesis still insufficient, andrm -rf .aspireis still the workaround.Suggest retitling to something like "aspire restore skips re-restore when switching back to a previously-built PR/hive package version, silently reusing the old code generator."
Narrow the stale-codegen caveat to what actually reproduces
Re-restore integrations when another CLI replaced the assets
joperezr commentedon Aug 22, 2026
🤖 Aspire triage pass — 2026-08-22 08:54 UTC
Area:
area-cli,area-atsKind: bug
Repro: yes-minimal — see the
## Reprosection (3-step version-switch sequence)Affected version(s):
13.5.1,13.6.0-pr.19577(dogfood PR build)Severity: S3 — only triggers on a newer→older→newer CLI version switch; workaround
rm -rf .aspireexists. Impact is a misleading silent success during codegen-fix validation.Urgency: ⚪ backlog — no milestone
Reason: build-staleness bug in
aspire restoreintegration-restore gating, not a confirmed regression, and a workaround exists. Default to backlog while 13.5 stabilizes; a human can pull it up if it's blocking codegen-fix validation more broadly.Suggested owner(s): Sébastien Ros (@sebastienros) (score 11), backup Mitch Denny (@mitchdenny) (score 6)
Evidence:
aspire update --migratepath from apphost.ts to apphost.mts #18294, Align TypeScript validation with package manager markers #17419, Optimize TypeScript compatibility checks #17415 inarea-atsarea-cli: Run CLI smoke tests across all PR platforms #19516, Sync ASP.NET Core certificate generation sources #19320, Honor ASPIRE_HOME for deployment state #19244area-cliauthor (Exclude unused hex1bpty.exe from published CLI archives #19554, Persist CLI channel across installs and self-updates #19469, [release/13.5] Fix mixed-quality staging package discovery #19427).aspire/**/obj/**artifacts), so CODEOWNERS scoring did not apply.Confidence: medium
Needs human?: no
Stamp every restore that ran, and say which check rejected the stamp
[-]aspire restore silently runs the previous CLI version's TypeScript code generator after a version switch[/-][+]aspire restore skips re-restore when switching back to a previously-built PR/hive package version, silently reusing the old code generator[/+][-]aspire restore skips re-restore when switching back to a previously-built PR/hive package version, silently reusing the old code generator[/-][+]aspire restore skips re-restore when an older CLI replaced the integration assets, silently reusing the old code generator[/+]flojon commentedon Aug 22, 2026
Correcting my own narrowing above — the PR/hive condition is confounded, and the
scope is wider than that comment concluded.
While verifying #19604 against this repro I checked what the intervening CLI
actually does.
13.5.1has no skip-restore logic at all. Its debug line is:where the
13.6.0-pr.19577build logs the same line with(restore requested)appended. Across three separate
13.5.1restores in the same directory the stampwas never created, read, or refreshed — it stayed at the dogfood run's value and
mtime throughout.
13.5.1simply always restores.So the two necessary conditions are about which CLI has the feature, not about
where its packages come from:
trusts it on the next launch
project.assets.json, and never touches the stamp, so the earlier stamp survivesintact and the returning CLI reproduces its own earlier fingerprint
The reason I couldn't reproduce it between two released versions is that neither
13.5.1nor13.5.2has the stamp logic yet — not that they were released ratherthan hive-sourced. The only stamp-aware build I had was a PR one, so "hive-sourced"
tracked "has the feature" perfectly and I read the wrong condition out of it.
That matters for severity. Once skip-restore ships in a release, this reproduces
between two plain released versions — newer-with-stamp → older-without-stamp →
newer-with-stamp — with no dogfood build involved. It's a latent general bug rather
than a PR-validation-only one, which I think undercuts the "only triggers on a
newer→older→newer CLI version switch, workaround exists" read in the triage pass.
Retitled accordingly. #19604 fixes it by binding the stamp to a fingerprint of the
assets it produced, which is version-agnostic and so covers the general case too,
not just the hive one I originally described.
Sharpen the stale-codegen caveat and link the upstream issue
Narrow the stale-codegen caveat to what actually reproduces
Unblock the TypeScript AppHost sample on Aspire CLI 13.6.0+ (#57)
flojon commentedon Oct 25, 2026
Update: #19763 removed the
aspire-restore.stampskip logic. On currentmain,PrebuiltAppHostServeralways restores (noRestore: false), so the version-switch sequence in this issue should no longer leave stale assets. I verified this by reading the code, not by re-running the repro on amainbuild. Builds that still contain the stamp logic (e.g. the 13.6.0-pr dogfood build) can still reproduce it. I've closed the fix PR #19604 as obsolete. Leaving this issue open for a maintainer to confirm and close.