Skip to content

Fix install script swallowing file-lock errors and reporting false success#15419

Draft
Copilot wants to merge 4 commits intomainfrom
copilot/fix-aspire-install-error-message
Draft

Fix install script swallowing file-lock errors and reporting false success#15419
Copilot wants to merge 4 commits intomainfrom
copilot/fix-aspire-install-error-message

Conversation

Copy link
Contributor

Copilot AI commented Mar 20, 2026

When aspire.exe was held open by another process during install, Move-Item in Backup-ExistingCliExecutable emitted a non-terminating error — PowerShell wrote to the error stream but kept executing. The backup path was pre-assigned before the Move-Item call, so the function returned a non-null path despite never creating the backup file. Expand-Archive then tried to overwrite the still-locked binary, also failed silently, and the catch block was never triggered — causing the script to print the success message against a failed install.

Changes (get-aspire-cli.ps1 and get-aspire-cli-pr.ps1)

  • Backup-ExistingCliExecutable: Wrap Move-Item with -ErrorAction Stop inside a try/catch. On failure, throw an actionable message:
    Failed to back up existing CLI at '...'. The file may be in use by another process.
    Please close any running Aspire CLI instances and try again.
    
  • Expand-AspireCliArchive (Windows): Add -ErrorAction Stop to Expand-Archive so extraction failures are terminating and caught by the existing catch block (which also restores the backup).
  • Expand-AspireCliArchive (Unix, get-aspire-cli.ps1 only): Add $LASTEXITCODE check after tar — the PR-variant already had this.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?
Original prompt

This section details on the original issue you should resolve

<issue_title>aspire install ps1 shows error message but then reports it succeeded when it didn't</issue_title>
<issue_description>On Windows, I had the staging channel of the CLI already installed.

Then I ran irm https://aspire.dev/install.ps1 | iex to install latest stable and this is what I saw:

➜ irm https://aspire.dev/install.ps1 | iex
Downloading aspire-cli-win-x64.zip from 'ga/daily'
Move-Item:
Line |
 636 |              Move-Item -Path $TargetExePath -Destination $backupPath - …
     |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The process cannot access the file because it is being used by another process.
Remove-Item: The process cannot access the file 'C:\Users\dedward\.aspire\bin\aspire.exe' because it is being used by another process.
Aspire CLI successfully installed to: C:\Users\dedward\.aspire\bin\aspire.exe

The aspire cli is now available for use in this and new sessions.

It seems it failed to perform the logical rename of the downloaded file because the existing aspire.exe was locked by another process. Oddly I couldn't find any instances of aspire.exe already running?

A few issues here:

  • The exception is uncaught and bubbles up as a raw error to the end user
  • The script continues and renders the success message
  • The install didn't actually succeed as I still have the staging version (13.2 in this case) installed

Image</issue_description>

<agent_instructions>Improve error handling so we correctly when the files cannot be moved to the target location. Also, look for other missing or ignored error handling.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

… success messages

When aspire.exe was locked by another process, Move-Item in
Backup-ExistingCliExecutable failed as a non-terminating error and execution
continued, causing Expand-Archive to also fail silently and the success
message to be displayed regardless.

- Wrap Move-Item in Backup-ExistingCliExecutable with try/catch +
  -ErrorAction Stop in both get-aspire-cli.ps1 and get-aspire-cli-pr.ps1,
  throwing a clear actionable message when the backup fails
- Add -ErrorAction Stop to Expand-Archive in both scripts so extraction
  failures are caught by the existing catch block
- Add exit-code check for tar in get-aspire-cli.ps1 (pr variant already had it)

Co-authored-by: radical <1472+radical@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix erroneous success message in aspire install ps1 Fix install script swallowing file-lock errors and reporting false success Mar 20, 2026
Copilot AI requested a review from radical March 20, 2026 01:00
@github-actions
Copy link
Contributor

github-actions bot commented Mar 20, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 15419

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 15419"

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@radical radical marked this pull request as ready for review March 20, 2026 03:42
Copilot AI review requested due to automatic review settings March 20, 2026 03:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves robustness of the Aspire CLI install PowerShell scripts by converting previously non-terminating file operation failures (notably when aspire.exe is locked) into terminating errors that are properly caught and reported, preventing false “success” output.

Changes:

  • Make backup/restore of existing CLI executable fail fast (-ErrorAction Stop) and surface an actionable error when backup can’t be created.
  • Ensure archive extraction failures are terminating (Expand-Archive -ErrorAction Stop) so the existing try/catch logic runs (including backup restore).
  • Add Unix tar exit-code validation in get-aspire-cli.ps1 (PR variant already had this behavior).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
eng/scripts/get-aspire-cli.ps1 Harden backup/restore + extraction paths to avoid swallowed errors and false success; add tar exit-code check.
eng/scripts/get-aspire-cli-pr.ps1 Align PR installer with the same backup/restore + extraction error handling improvements.

Comment on lines +667 to 668
Move-Item -Path $BackupPath -Destination $TargetExePath -Force -ErrorAction Stop
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restore-CliExecutableFromBackup now uses Move-Item -ErrorAction Stop, which will throw if the restore fails (e.g., the target is still locked). In Expand-AspireCliArchive the restore call is not wrapped, so a restore failure will short-circuit the catch block and can mask the original extraction failure. Consider catching restore errors inside Expand-AspireCliArchive and either (a) include both the original extraction error and the restore error in the final thrown message, or (b) log the restore error and still rethrow the original extraction failure.

Copilot uses AI. Check for mistakes.
}

Move-Item -Path $BackupPath -Destination $TargetExePath -Force
Move-Item -Path $BackupPath -Destination $TargetExePath -Force -ErrorAction Stop
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restore-CliExecutableFromBackup now uses Move-Item -ErrorAction Stop, which will throw if the restore fails (e.g., the target is still locked). In Expand-AspireCliArchive the restore call in the catch block isn’t wrapped, so a restore failure will abort the catch block and can hide the original extraction error. Consider handling restore failures inside Expand-AspireCliArchive so the final error surfaced to the user retains the primary failure cause while still reporting any restore failure.

Suggested change
Move-Item -Path $BackupPath -Destination $TargetExePath -Force -ErrorAction Stop
try {
Move-Item -Path $BackupPath -Destination $TargetExePath -Force -ErrorAction Stop
}
catch {
# Do not rethrow here: this runs during error recovery and should not mask the original failure.
Write-Message "Failed to restore CLI from backup '$BackupPath' to '$TargetExePath'. The backup file may be in use or the target may be locked. Error: $($_.Exception.Message)" -Level Warning
}

Copilot uses AI. Check for mistakes.
@radical radical marked this pull request as draft March 20, 2026 03:51
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment on lines 635 to +640
# Rename existing executable to .old.[timestamp]
Move-Item -Path $TargetExePath -Destination $backupPath -Force
try {
Move-Item -Path $TargetExePath -Destination $backupPath -Force -ErrorAction Stop
}
catch {
throw "Failed to back up existing CLI at '$TargetExePath'. The file may be in use by another process. Please close any running Aspire CLI instances and try again. Error: $($_.Exception.Message)"
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backup-ExistingCliExecutable now correctly fails when Move-Item can’t back up a locked executable, but the surrounding wording (“allows installation to proceed even when the CLI is running” / “file can be renamed”) can be misleading because rename may still fail depending on the handle’s sharing mode. Consider updating the nearby comment/message to clarify that the script attempts to rename and will stop with an actionable error if the file can’t be moved (e.g., locked by another process).

Copilot uses AI. Check for mistakes.
Comment on lines 744 to +746
& tar -xzf $ArchiveFile
if ($LASTEXITCODE -ne 0) {
throw "tar command failed with exit code $LASTEXITCODE"
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thrown tar failure message currently only includes the exit code. Including $ArchiveFile (and ideally tar’s stderr/stdout) would make failures much easier to diagnose, especially when multiple archives/paths are involved.

Suggested change
& tar -xzf $ArchiveFile
if ($LASTEXITCODE -ne 0) {
throw "tar command failed with exit code $LASTEXITCODE"
$tarOutput = & tar -xzf $ArchiveFile 2>&1
$tarExitCode = $LASTEXITCODE
if ($tarExitCode -ne 0) {
$message = "tar command failed for archive '$ArchiveFile' with exit code $tarExitCode."
if ($tarOutput) {
$message += " Output:`n$tarOutput"
}
throw $message

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Contributor

Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

@github-actions
Copy link
Contributor

🎬 CLI E2E Test Recordings — 52 recordings uploaded (commit 1830f02)

View recordings
Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_DefaultSelection_InstallsSkillOnly ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
CertificatesClean_RemovesCertificates ▶️ View Recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View Recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View Recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View Recording
CreateAndDeployToDockerCompose ▶️ View Recording
CreateAndDeployToDockerComposeInteractive ▶️ View Recording
CreateAndPublishToKubernetes ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunEmptyAppHostProject ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateStartAndStopAspireProject ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View Recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View Recording
GlobalMigration_PreservesAllValueTypes ▶️ View Recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View Recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View Recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View Recording
RestoreGeneratesSdkFiles ▶️ View Recording
RunWithMissingAwaitShowsHelpfulError ▶️ View Recording
SecretCrudOnDotNetAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopAllAppHostsFromUnrelatedDirectory ▶️ View Recording
StopNonInteractiveMultipleAppHostsShowsError ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording
TypeScriptAppHostWithProjectReferenceIntegration ▶️ View Recording

📹 Recordings uploaded automatically from CI run #23328308198

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

aspire install ps1 shows error message but then reports it succeeded when it didn't

3 participants