Epic Games Launcher stuck on Resume after UE 5.8.2 update – manifest commit never completes

Update: confirmed workaround + safe PowerShell diagnostic

Another user has now reported what appears to be the same UE 5.8.1 → 5.8.2 Launcher issue, so I am adding the diagnostic/workaround I used to recover my installation.

Important clarification

In my case, the very first UE 5.8.1 → 5.8.2 Update attempt had already updated the actual Engine files successfully.

After that first Update:

UnrealEditor.exe
Numeric FileVersion: 5.8.2.0
ProductVersion: ++UE5+Release-5.8-CL-56702186

Engine\Build\Build.version
Version: 5.8.2
Changelist: 56702186

However, Epic Games Launcher still displayed:

5.8.1
Resume

Clicking Resume/Update again downloaded no meaningful Engine data and returned to Resume.

The Launcher log showed that BuildPatch itself completed successfully:

ProcessSuccess: TRUE
ErrorCode: OK
FailureReasonText: The operation was successful.

but afterwards remained at:

IncompleteInstall=1 AutoResume=1
completed, waiting for manifest commit before starting next download

Therefore this workaround is not intended to force-install UE 5.8.2. It only attempts to reconcile the Launcher metadata when the actual Engine has already been successfully updated to 5.8.2 / CL 56702186.


PowerShell diagnostic / workaround

The script is deliberately READ-ONLY by default:

$ApplyChanges = $false

In this mode it:

  • locates the installed UE_5.8 Launcher metadata automatically,
  • verifies UnrealEditor.exe,
  • verifies Engine\Build\Build.version,
  • verifies the installed manifest,
  • checks LauncherInstalled.dat,
  • detects the active UE 5.8 pending transaction,
  • validates the pending UE 5.8.2 metadata,
  • simulates the final metadata commit in memory only.

It does not modify, copy or delete anything.

If the system is already fixed, the script exits with:

STATUS: ALREADY HEALTHY
UE 5.8.2 metadata is already committed.
No active UE 5.8 Pending transaction exists.
No changes were made.

I tested this state after recovering my installation and the script correctly detected the healthy UE 5.8.2 installation.

If the problem is present, the expected diagnostic result is:

STATUS: AFFECTED / CONDITIONS MATCH

Physical Engine:
  UE 5.8.2 / CL 56702186

Installed metadata:
  5.8.1-56057345+++UE5+Release-5.8-Windows

Pending target:
  5.8.2-56702186+++UE5+Release-5.8-Windows

In-memory commit simulation:
  PASSED

DRY RUN PASSED
No files were modified, copied or deleted.

Only after DRY RUN PASSED, the same script can be changed to:

$ApplyChanges = $true

The Apply mode creates a complete backup before changing anything, then asks the user to completely exit Epic Games Launcher and explicitly type:

APPLY

before performing the metadata reconciliation.

The backup contains the installed .item, Pending .item, installed manifest, Pending manifest, LauncherInstalled.dat and Build.version.

The script removes only the UE 5.8-specific pending transaction and does not remove the entire Pending directory.

In my case, after the workaround and restarting Epic Games Launcher, it immediately displayed:

Unreal Engine 5.8.2
Launch

No additional Engine download was required.

Warning

This is an unofficial workaround, not an Epic fix.

Do not use Apply mode unless the DRY-RUN confirms that the physical Engine is already exactly UE 5.8.2 / CL 56702186 and the remaining problem is the Launcher metadata/pending transaction.

Keep the automatically-created backup until Epic provides an official fix.

Tip: The copy button for the full script is in the top-right corner of the code block.

& {
    $ErrorActionPreference = "Stop"
    Set-StrictMode -Version Latest


    # ============================================================
    # MODE
    # ============================================================
    #
    # DEFAULT = SAFE / READ-ONLY
    #
    # Leave this as $false first.
    #
    # Change to $true ONLY after DRY RUN PASSED and only if the
    # system matches the issue described in this thread.
    #
    # ============================================================

    $ApplyChanges = $false


    # ============================================================
    # EXPECTED UE BUILD
    # ============================================================

    $ExpectedAppVersion =
        "5.8.2-56702186+++UE5+Release-5.8-Windows"

    $PreviousAppVersion =
        "5.8.1-56057345+++UE5+Release-5.8-Windows"

    $ExpectedMajor = 5
    $ExpectedMinor = 8
    $ExpectedPatch = 2
    $ExpectedCL    = 56702186


    # ============================================================
    # LAUNCHER PATHS
    # ============================================================

    $ManifestRoot =
        "C:\ProgramData\Epic\EpicGamesLauncher\Data\Manifests"

    $PendingRoot =
        Join-Path $ManifestRoot "Pending"

    $LauncherDat =
        "C:\ProgramData\Epic\UnrealEngineLauncher\LauncherInstalled.dat"


    # ============================================================
    # HELPER
    # ============================================================

    function Read-JsonFile {
        param(
            [Parameter(Mandatory = $true)]
            [string]$Path
        )

        Get-Content -LiteralPath $Path -Raw |
            ConvertFrom-Json
    }


    Write-Host ""
    Write-Host "==========================================="
    Write-Host " UE 5.8.2 LAUNCHER MANIFEST DIAGNOSTIC"
    Write-Host "==========================================="

    if ($ApplyChanges) {
        Write-Host "MODE: APPLY CHANGES"
    }
    else {
        Write-Host "MODE: DRY RUN / READ-ONLY"
    }


    # ============================================================
    # 1. FIND INSTALLED UE_5.8 ITEM
    # ============================================================

    if (-not (Test-Path $ManifestRoot)) {
        throw "STOP: Epic Games Launcher manifest directory was not found."
    }

    $MainCandidates = @(
        Get-ChildItem `
            -LiteralPath $ManifestRoot `
            -Filter "*.item" `
            -File |
        ForEach-Object {

            try {
                $J = Read-JsonFile $_.FullName

                if ($J.AppName -eq "UE_5.8") {
                    [PSCustomObject]@{
                        Path = $_.FullName
                        Data = $J
                    }
                }
            }
            catch {
                # Ignore unrelated/unreadable item files.
            }
        }
    )

    if ($MainCandidates.Count -ne 1) {
        throw "STOP: Expected exactly one installed UE_5.8 item, found $($MainCandidates.Count)."
    }

    $MainItemPath =
        $MainCandidates[0].Path

    $Main =
        $MainCandidates[0].Data

    Write-Host ""
    Write-Host "[1] Installed UE_5.8 metadata"
    Write-Host "Item       : $MainItemPath"
    Write-Host "Version    : $($Main.AppVersionString)"
    Write-Host "Incomplete : $($Main.bIsIncompleteInstall)"
    Write-Host "Location   : $($Main.InstallLocation)"


    # ============================================================
    # 2. VERIFY PHYSICAL UNREAL ENGINE
    # ============================================================

    if ([string]::IsNullOrWhiteSpace($Main.InstallLocation)) {
        throw "STOP: UE_5.8 InstallLocation is empty."
    }

    $EditorExe =
        Join-Path `
            $Main.InstallLocation `
            "Engine\Binaries\Win64\UnrealEditor.exe"

    if (-not (Test-Path $EditorExe)) {
        throw "STOP: UnrealEditor.exe was not found."
    }

    $VI =
        (Get-Item $EditorExe).VersionInfo

    $NumericFileVersion =
        "{0}.{1}.{2}.{3}" -f `
            $VI.FileMajorPart,
            $VI.FileMinorPart,
            $VI.FileBuildPart,
            $VI.FilePrivatePart

    Write-Host ""
    Write-Host "[2] Physical UnrealEditor.exe"
    Write-Host "Numeric FileVersion : $NumericFileVersion"
    Write-Host "FileVersion string  : $($VI.FileVersion)"
    Write-Host "ProductVersion      : $($VI.ProductVersion)"

    if (
        $VI.FileMajorPart -ne $ExpectedMajor -or
        $VI.FileMinorPart -ne $ExpectedMinor -or
        $VI.FileBuildPart -ne $ExpectedPatch
    ) {
        throw "STOP: UnrealEditor.exe is not UE 5.8.2."
    }

    if ($VI.ProductVersion -notlike "*CL-$ExpectedCL*") {
        throw "STOP: UnrealEditor.exe is not CL $ExpectedCL."
    }


    # ============================================================
    # 3. VERIFY Engine\Build\Build.version
    # ============================================================

    $BuildVersionPath =
        Join-Path `
            $Main.InstallLocation `
            "Engine\Build\Build.version"

    if (-not (Test-Path $BuildVersionPath)) {
        throw "STOP: Engine\Build\Build.version was not found."
    }

    $Build =
        Read-JsonFile $BuildVersionPath

    Write-Host ""
    Write-Host "[3] Engine Build.version"
    Write-Host "Version    : $($Build.MajorVersion).$($Build.MinorVersion).$($Build.PatchVersion)"
    Write-Host "Changelist : $($Build.Changelist)"

    if (
        $Build.MajorVersion -ne $ExpectedMajor -or
        $Build.MinorVersion -ne $ExpectedMinor -or
        $Build.PatchVersion -ne $ExpectedPatch -or
        $Build.Changelist -ne $ExpectedCL
    ) {
        throw "STOP: Build.version does not report UE 5.8.2 / CL $ExpectedCL."
    }


    # ============================================================
    # 4. VERIFY INSTALLED MANIFEST
    # ============================================================

    if ([string]::IsNullOrWhiteSpace($Main.CompleteManifestPath)) {
        throw "STOP: CompleteManifestPath is empty."
    }

    if (-not (Test-Path $Main.CompleteManifestPath)) {
        throw "STOP: Installed manifest does not exist: $($Main.CompleteManifestPath)"
    }

    $InstalledManifestHash =
        (Get-FileHash `
            $Main.CompleteManifestPath `
            -Algorithm SHA256).Hash

    Write-Host ""
    Write-Host "[4] Installed manifest"
    Write-Host "Path   : $($Main.CompleteManifestPath)"
    Write-Host "SHA256 : $InstalledManifestHash"


    # ============================================================
    # 5. READ LauncherInstalled.dat
    # ============================================================

    if (-not (Test-Path $LauncherDat)) {
        throw "STOP: LauncherInstalled.dat was not found."
    }

    $Launcher =
        Read-JsonFile $LauncherDat

    $UE58Entries = @(
        $Launcher.InstallationList |
        Where-Object {
            $_.AppName -eq "UE_5.8"
        }
    )

    if ($UE58Entries.Count -ne 1) {
        throw "STOP: Expected exactly one UE_5.8 entry in LauncherInstalled.dat."
    }

    $UE58 =
        $UE58Entries[0]

    Write-Host ""
    Write-Host "[5] LauncherInstalled.dat"
    Write-Host "AppName    : $($UE58.AppName)"
    Write-Host "AppVersion : $($UE58.AppVersion)"


    # ============================================================
    # 6. FIND ACTIVE UE_5.8 PENDING TRANSACTION
    # ============================================================

    $PendingCandidates = @()

    if (Test-Path $PendingRoot) {

        $PendingCandidates = @(
            Get-ChildItem `
                -LiteralPath $PendingRoot `
                -Filter "*.item" `
                -File `
                -ErrorAction SilentlyContinue |
            ForEach-Object {

                try {
                    $J = Read-JsonFile $_.FullName

                    if ($J.AppName -eq "UE_5.8") {
                        [PSCustomObject]@{
                            Path = $_.FullName
                            Data = $J
                        }
                    }
                }
                catch {
                    # Ignore unrelated/unreadable Pending items.
                }
            }
        )
    }


    # ============================================================
    # ALREADY HEALTHY?
    # ============================================================

    if ($PendingCandidates.Count -eq 0) {

        if (
            $Main.AppVersionString -eq $ExpectedAppVersion -and
            $Main.bIsIncompleteInstall -eq $false -and
            $UE58.AppVersion -eq $ExpectedAppVersion
        ) {

            Write-Host ""
            Write-Host "==========================================="
            Write-Host " STATUS: ALREADY HEALTHY"
            Write-Host "==========================================="
            Write-Host "UE 5.8.2 metadata is already committed."
            Write-Host "No active UE 5.8 Pending transaction exists."
            Write-Host "No changes were made."
            Write-Host "==========================================="

            return
        }

        Write-Host ""
        Write-Host "==========================================="
        Write-Host " STATUS: PENDING TRANSACTION NOT FOUND"
        Write-Host "==========================================="
        Write-Host ""
        Write-Host "The physical Engine is UE 5.8.2, but no active"
        Write-Host "UE_5.8 Pending transaction was found."
        Write-Host ""
        Write-Host "If Epic Games Launcher is stuck on Update/Resume:"
        Write-Host ""
        Write-Host "1. Open Epic Games Launcher."
        Write-Host "2. Click Update/Resume once."
        Write-Host "3. Wait until it returns to Resume."
        Write-Host "4. Run this script again BEFORE closing Launcher."
        Write-Host ""
        Write-Host "No changes were made."
        Write-Host "==========================================="

        return
    }


    if ($PendingCandidates.Count -ne 1) {
        throw "STOP: More than one UE_5.8 Pending item was found."
    }

    $PendingItemPath =
        $PendingCandidates[0].Path

    $Pending =
        $PendingCandidates[0].Data

    Write-Host ""
    Write-Host "[6] Active Pending transaction"
    Write-Host "Item       : $PendingItemPath"
    Write-Host "Version    : $($Pending.AppVersionString)"
    Write-Host "Incomplete : $($Pending.bIsIncompleteInstall)"
    Write-Host "PrereqSHA1 : $($Pending.PrereqSHA1Hash)"


    # ============================================================
    # 7. VALIDATE PENDING METADATA
    # ============================================================

    if ($Pending.AppVersionString -ne $ExpectedAppVersion) {
        throw "STOP: Pending transaction is not UE 5.8.2 / CL $ExpectedCL."
    }

    if ($Pending.bIsIncompleteInstall -ne $true) {
        throw "STOP: Pending UE_5.8 item is not marked as incomplete."
    }

    if (
        [string]::IsNullOrWhiteSpace($Pending.PrereqSHA1Hash) -or
        $Pending.PrereqSHA1Hash -notmatch '^[0-9A-Fa-f]{40}$'
    ) {
        throw "STOP: Pending PrereqSHA1Hash is invalid."
    }

    if (
        -not [string]::IsNullOrWhiteSpace($Pending.InstallLocation) -and
        $Pending.InstallLocation -ne $Main.InstallLocation
    ) {
        throw "STOP: Pending InstallLocation does not match installed UE_5.8."
    }


    # ============================================================
    # 8. LOCATE PENDING MANIFEST
    # ============================================================

    if ([string]::IsNullOrWhiteSpace($Main.PendingManifestPath)) {
        throw "STOP: Installed UE_5.8 item has no PendingManifestPath."
    }

    $PendingManifestPath =
        $Main.PendingManifestPath

    if (-not (Test-Path $PendingManifestPath)) {
        throw "STOP: Pending UE 5.8 manifest was not found: $PendingManifestPath"
    }

    $PendingManifestHash =
        (Get-FileHash `
            $PendingManifestPath `
            -Algorithm SHA256).Hash

    Write-Host ""
    Write-Host "[7] Pending manifest"
    Write-Host "Path   : $PendingManifestPath"
    Write-Host "SHA256 : $PendingManifestHash"


    # ============================================================
    # 9. VALIDATE CURRENT METADATA VERSION
    # ============================================================

    $AllowedInstalledVersions =
        @(
            $PreviousAppVersion,
            $ExpectedAppVersion
        )

    if ($Main.AppVersionString -notin $AllowedInstalledVersions) {
        throw "STOP: Installed metadata contains an unexpected UE_5.8 version."
    }

    if ($UE58.AppVersion -notin $AllowedInstalledVersions) {
        throw "STOP: LauncherInstalled.dat contains an unexpected UE_5.8 version."
    }


    # ============================================================
    # 10. SIMULATE THE MANIFEST COMMIT IN MEMORY
    # ============================================================

    $SimMain =
        Read-JsonFile $MainItemPath

    $SimMain.AppVersionString =
        $Pending.AppVersionString

    $SimMain.PrereqSHA1Hash =
        $Pending.PrereqSHA1Hash

    $SimMain.bIsIncompleteInstall =
        $false


    $SimLauncher =
        Read-JsonFile $LauncherDat

    $SimEntries = @(
        $SimLauncher.InstallationList |
        Where-Object {
            $_.AppName -eq "UE_5.8"
        }
    )

    if ($SimEntries.Count -ne 1) {
        throw "STOP: Simulation could not uniquely resolve UE_5.8."
    }

    $SimEntries[0].AppVersion =
        $ExpectedAppVersion


    # Serialize + parse again to verify that resulting JSON remains valid.

    $SimMainJson =
        $SimMain |
        ConvertTo-Json -Depth 20

    $SimLauncherJson =
        $SimLauncher |
        ConvertTo-Json -Depth 20

    $ParsedMain =
        $SimMainJson |
        ConvertFrom-Json

    $ParsedLauncher =
        $SimLauncherJson |
        ConvertFrom-Json

    $ParsedUE58 = @(
        $ParsedLauncher.InstallationList |
        Where-Object {
            $_.AppName -eq "UE_5.8"
        }
    )

    if ($ParsedMain.AppVersionString -ne $ExpectedAppVersion) {
        throw "STOP: In-memory installed metadata simulation failed."
    }

    if ($ParsedMain.PrereqSHA1Hash -ne $Pending.PrereqSHA1Hash) {
        throw "STOP: In-memory PrereqSHA1Hash simulation failed."
    }

    if ($ParsedMain.bIsIncompleteInstall -ne $false) {
        throw "STOP: Simulated installed metadata remains incomplete."
    }

    if (
        $ParsedUE58.Count -ne 1 -or
        $ParsedUE58[0].AppVersion -ne $ExpectedAppVersion
    ) {
        throw "STOP: LauncherInstalled.dat simulation failed."
    }


    # ============================================================
    # DRY RUN RESULT
    # ============================================================

    Write-Host ""
    Write-Host "==========================================="
    Write-Host " STATUS: AFFECTED / CONDITIONS MATCH"
    Write-Host "==========================================="
    Write-Host ""
    Write-Host "Physical Engine:"
    Write-Host "  UE 5.8.2 / CL $ExpectedCL"
    Write-Host ""
    Write-Host "Installed metadata:"
    Write-Host "  $($Main.AppVersionString)"
    Write-Host ""
    Write-Host "Pending target:"
    Write-Host "  $($Pending.AppVersionString)"
    Write-Host ""
    Write-Host "LauncherInstalled.dat:"
    Write-Host "  $($UE58.AppVersion)"
    Write-Host ""
    Write-Host "In-memory commit simulation:"
    Write-Host "  PASSED"


    if (-not $ApplyChanges) {

        Write-Host ""
        Write-Host "==========================================="
        Write-Host " DRY RUN PASSED"
        Write-Host "==========================================="
        Write-Host "No files were modified, copied or deleted."
        Write-Host ""
        Write-Host "To apply the workaround:"
        Write-Host ""
        Write-Host 'Change: $ApplyChanges = $false'
        Write-Host 'To:     $ApplyChanges = $true'
        Write-Host ""
        Write-Host "Then run THIS SAME script again while"
        Write-Host "the Launcher is still in the Resume state."
        Write-Host "==========================================="

        return
    }


    # ============================================================
    # APPLY MODE
    # ============================================================
    #
    # From this point on changes are allowed.
    #
    # First create a complete backup while the Pending transaction
    # still exists. Only after that will the user be asked to close
    # Epic Games Launcher.
    #
    # ============================================================

    Write-Host ""
    Write-Host "==========================================="
    Write-Host " APPLY MODE - CREATING BACKUP"
    Write-Host "==========================================="


    $Desktop =
        [Environment]::GetFolderPath(
            [Environment+SpecialFolder]::Desktop
        )

    $Stamp =
        Get-Date -Format "yyyyMMdd_HHmmss"

    $BackupDir =
        Join-Path `
            $Desktop `
            "UE58_LauncherBackup_$Stamp"

    New-Item `
        -Path $BackupDir `
        -ItemType Directory |
        Out-Null


    Copy-Item `
        -LiteralPath $MainItemPath `
        -Destination (Join-Path $BackupDir "installed.item")

    Copy-Item `
        -LiteralPath $PendingItemPath `
        -Destination (Join-Path $BackupDir "pending.item")

    Copy-Item `
        -LiteralPath $Main.CompleteManifestPath `
        -Destination (Join-Path $BackupDir "installed.manifest")

    Copy-Item `
        -LiteralPath $PendingManifestPath `
        -Destination (Join-Path $BackupDir "pending.manifest")

    Copy-Item `
        -LiteralPath $LauncherDat `
        -Destination (Join-Path $BackupDir "LauncherInstalled.dat")

    Copy-Item `
        -LiteralPath $BuildVersionPath `
        -Destination (Join-Path $BackupDir "Build.version")


    Write-Host ""
    Write-Host "BACKUP CREATED:"
    Write-Host $BackupDir
    Write-Host ""
    Write-Host "Do NOT delete this backup until Epic provides"
    Write-Host "an official fix or you are satisfied with the result."


    # ============================================================
    # USER CONFIRMATION
    # ============================================================

    Write-Host ""
    Write-Host "Now completely EXIT Epic Games Launcher,"
    Write-Host "including the system tray icon."
    Write-Host ""
    Write-Host "The Pending files may disappear when Launcher exits."
    Write-Host "That is OK - copies are already stored in the backup."
    Write-Host ""

    $Confirm =
        Read-Host "After Launcher is fully closed, type APPLY"

    if ($Confirm -cne "APPLY") {
        Write-Host ""
        Write-Host "Cancelled."
        Write-Host "No Launcher metadata was modified."
        Write-Host "The backup directory was kept:"
        Write-Host $BackupDir

        return
    }


    # ============================================================
    # VERIFY LAUNCHER IS REALLY CLOSED
    # ============================================================

    $Running =
        Get-Process `
            EpicGamesLauncher,
            EpicWebHelper `
            -ErrorAction SilentlyContinue

    if ($Running) {
        throw "STOP: Epic Games Launcher or EpicWebHelper is still running. No metadata commit was performed."
    }


    # ============================================================
    # RE-READ BACKUP SOURCES
    # ============================================================

    $BackupMain =
        Read-JsonFile `
            (Join-Path $BackupDir "installed.item")

    $BackupPending =
        Read-JsonFile `
            (Join-Path $BackupDir "pending.item")


    if ($BackupPending.AppVersionString -ne $ExpectedAppVersion) {
        throw "STOP: Backup Pending metadata is not the expected UE 5.8.2 build."
    }


    # ============================================================
    # 11. PROMOTE COMPLETED PENDING MANIFEST TO INSTALLED MANIFEST
    # ============================================================

    Copy-Item `
        -LiteralPath (Join-Path $BackupDir "pending.manifest") `
        -Destination $BackupMain.CompleteManifestPath `
        -Force


    # ============================================================
    # 12. COMMIT INSTALLED ITEM METADATA
    # ============================================================

    #
    # Keep the structure and install options from the original
    # installed item.
    #
    # Only promote fields that are known to belong to the new build.
    #

    $BackupMain.AppVersionString =
        $BackupPending.AppVersionString

    $BackupMain.PrereqSHA1Hash =
        $BackupPending.PrereqSHA1Hash

    $BackupMain.bIsIncompleteInstall =
        $false


    $CommittedItemJson =
        $BackupMain |
        ConvertTo-Json -Depth 20


    $Utf8NoBom =
        New-Object System.Text.UTF8Encoding($false)

    [IO.File]::WriteAllText(
        $MainItemPath,
        $CommittedItemJson,
        $Utf8NoBom
    )


    # ============================================================
    # 13. UPDATE LauncherInstalled.dat
    # ============================================================

    #
    # Re-read the current file after Launcher shutdown so that
    # unrelated Launcher entries are preserved.
    #

    $CurrentLauncher =
        Read-JsonFile $LauncherDat

    $CurrentUE58 = @(
        $CurrentLauncher.InstallationList |
        Where-Object {
            $_.AppName -eq "UE_5.8"
        }
    )

    if ($CurrentUE58.Count -ne 1) {
        throw "STOP: UE_5.8 could not be uniquely resolved in LauncherInstalled.dat."
    }

    $CurrentUE58[0].AppVersion =
        $ExpectedAppVersion


    $CommittedLauncherJson =
        $CurrentLauncher |
        ConvertTo-Json -Depth 20

    [IO.File]::WriteAllText(
        $LauncherDat,
        $CommittedLauncherJson,
        $Utf8NoBom
    )


    # ============================================================
    # 14. REMOVE ONLY THE UE_5.8 PENDING TRANSACTION
    # ============================================================

    #
    # Launcher may already have removed these files on shutdown.
    # Therefore existence is checked first.
    #

    if (Test-Path $PendingItemPath) {
        Remove-Item `
            -LiteralPath $PendingItemPath
    }

    if (Test-Path $PendingManifestPath) {
        Remove-Item `
            -LiteralPath $PendingManifestPath
    }


    # ============================================================
    # 15. FINAL VERIFICATION
    # ============================================================

    $FinalMain =
        Read-JsonFile $MainItemPath

    $FinalLauncher =
        Read-JsonFile $LauncherDat

    $FinalUE58 = @(
        $FinalLauncher.InstallationList |
        Where-Object {
            $_.AppName -eq "UE_5.8"
        }
    )

    if ($FinalMain.AppVersionString -ne $ExpectedAppVersion) {
        throw "FINAL VERIFY FAILED: installed item version mismatch."
    }

    if ($FinalMain.bIsIncompleteInstall -ne $false) {
        throw "FINAL VERIFY FAILED: installed item is still incomplete."
    }

    if ($FinalMain.PrereqSHA1Hash -ne $BackupPending.PrereqSHA1Hash) {
        throw "FINAL VERIFY FAILED: PrereqSHA1Hash mismatch."
    }

    if (
        $FinalUE58.Count -ne 1 -or
        $FinalUE58[0].AppVersion -ne $ExpectedAppVersion
    ) {
        throw "FINAL VERIFY FAILED: LauncherInstalled.dat mismatch."
    }


    $FinalInstalledManifestHash =
        (Get-FileHash `
            $FinalMain.CompleteManifestPath `
            -Algorithm SHA256).Hash

    $BackupPendingManifestHash =
        (Get-FileHash `
            (Join-Path $BackupDir "pending.manifest") `
            -Algorithm SHA256).Hash

    if ($FinalInstalledManifestHash -ne $BackupPendingManifestHash) {
        throw "FINAL VERIFY FAILED: installed manifest does not match the completed Pending manifest."
    }


    Write-Host ""
    Write-Host "==========================================="
    Write-Host " WORKAROUND COMPLETED SUCCESSFULLY"
    Write-Host "==========================================="
    Write-Host ""
    Write-Host "Installed metadata:"
    Write-Host "  $($FinalMain.AppVersionString)"
    Write-Host ""
    Write-Host "Incomplete:"
    Write-Host "  $($FinalMain.bIsIncompleteInstall)"
    Write-Host ""
    Write-Host "LauncherInstalled.dat:"
    Write-Host "  $($FinalUE58[0].AppVersion)"
    Write-Host ""
    Write-Host "Pending item exists:"
    Write-Host "  $(Test-Path $PendingItemPath)"
    Write-Host ""
    Write-Host "Pending manifest exists:"
    Write-Host "  $(Test-Path $PendingManifestPath)"
    Write-Host ""
    Write-Host "Installed manifest SHA256:"
    Write-Host "  $FinalInstalledManifestHash"
    Write-Host ""
    Write-Host "Backup:"
    Write-Host "  $BackupDir"
    Write-Host ""
    Write-Host "You can now start Epic Games Launcher."
    Write-Host "It should display Unreal Engine 5.8.2 / Launch."
    Write-Host "==========================================="
}

Validation

Before publishing this workaround I tested the script in several modes.

  • The default read-only mode was tested against my repaired installation and correctly returned STATUS: ALREADY HEALTHY without modifying anything.
  • ApplyChanges = $true was also tested against the healthy installation and correctly exited without making changes.
  • The complete Apply workflow was then tested in an isolated sandbox created from the original files captured while the Launcher was affected:
Installed metadata: 5.8.1
Pending target:      5.8.2
Launcher metadata:   5.8.1

The sandbox test successfully performed the backup, manifest promotion, metadata reconciliation and Pending cleanup.

Final verification confirmed that the installed manifest SHA256 was identical to the original 5.8.2 Pending manifest SHA256:

9CB3C546C7D3C8C111D6D8AD69FE090714F5304FF1F81E099BD95B9F7493C86D

The real Epic Games Launcher and Unreal Engine installation were not modified during this sandbox test.