Epic Games Launcher UE 5.8.x Resume Loop — Stale ManifestHash (Possible Root Cause) [Workaround v3.3]

Final Investigation Update — October 2026 (Workaround v3.3)

Status: RESOLVED on my installation — UE 5.8.3 → 5.8.4

After further investigation, I identified a specific stale ManifestHash value in the live Epic Games Launcher .item metadata as a possible trigger for the persistent Resume loop.

A controlled experiment confirmed that clearing only this value allowed EGL to prepare the expected EOSH pending transaction and successfully complete the update to UE 5.8.4.

Key findings:

  • The manifest commit callback was present in the logs. The earlier description suggesting that it never completed was therefore too broad.

  • During the failing update attempts, BuildPatch activity completed, but the expected EOSH pending-to-installed transition did not occur.

  • Clearing the specific stale ManifestHash allowed EOSH to advance normally through its pending and finalization stages.

  • The completed installation passed manifest SHA256 checks and EGL displayed Launch.

  • The final workaround was validated using authentic pre-repair metadata, byte-identical SHA256 comparisons, and positive and negative safety tests.

Final workaround: UE58_ResumeFix_v3_3_Final.ps1

The script performs three operations: Audit → Apply → Verify. It creates backups and modifies only the confirmed ManifestHash value when the installation matches the tested conditions.

Important: This is a confirmed workaround for my specific UE 5.8.3 → 5.8.4 installation state, not a universal fix for all Resume loops. The exact internal root cause still requires confirmation by Epic.

Full technical report and download

The complete v3.3 investigation, including EGL/EOSH state transitions, manifest checksums, the downloadable PowerShell workaround, advanced manual instructions, and validation results, is available in my latest detailed reply below.

Please refer to Workaround v3.3 for the latest findings.


Previous Update — October 2026 (Workaround v2)

The earlier v2 workaround was independently confirmed by another affected user after reinstalling Unreal Engine failed to resolve the problem.

The original v2 findings and validation history are preserved below for reference.

Update – October 2026

The workaround has now been independently confirmed by another user.

They first tried a full uninstall/reinstall of UE 5.8, but the issue remained unchanged.

After that, they used the PowerShell v2.0 workaround from this thread and confirmed that it solved the problem:

“The uninstall/reinstall didn’t help at all. I ended up using your PowerShell script which solved the issue. Many thanks!”

This is important because it independently confirms that:

  • reinstalling the Engine does not necessarily fix the problem
  • the physical Engine installation itself is not necessarily corrupted
  • the issue is consistent with a stale/incomplete Launcher manifest state
  • the v2.0 workaround can restore the Launcher to the correct installed state

At this point, the v2.0 workaround has been successfully validated on:

  • my reproduced UE 5.8.1 → 5.8.2 failure
  • my reproduced UE 5.8.2 → 5.8.3 failure
  • an independent UE 5.8.x affected installation reported by another user

The Epic ticket UE-398557 was later closed as a duplicate of an existing known issue.

The parent/original issue ID has not yet been publicly identified in this thread.

Recommended action: before reinstalling UE 5.8, use the Workaround v2.0 below.

It runs in read-only DRY-RUN mode by default and can confirm whether your installation matches the same manifest-commit issue before making any changes.

Update – September 2026

This issue has now been reproduced on both UE 5.8.1 → 5.8.2 and UE 5.8.2 → 5.8.3.

Epic has opened UE-398557, currently marked Ready for QA.

I also added a generic PowerShell diagnostic/workaround v2.0 below. It automatically detects the affected UE 5.8.x target version from the Pending transaction and runs in read-only DRY-RUN mode by default.

Use v2.0 instead of the older 5.8.2-specific workaround.

Summary

Epic Games Launcher gets stuck in a Resume loop after updating Unreal Engine 5.8.1 to 5.8.2.

The engine files are successfully updated to UE 5.8.2 / CL 56702186, and BuildPatch reports ProcessSuccess=TRUE / ErrorCode=OK. However, the Launcher fails to commit the final installed manifest and returns to Resume without downloading anything.

The Launcher log shows:
IncompleteInstall=1 AutoResume=1
followed by:
completed, waiting for manifest commit before starting next download

There is also a suspicious MainGameAppId mismatch where the valid on-disk AppId is reconciled against catalog=(null):(null):(null).

What Type of Bug are you experiencing?

Other

Steps to Reproduce

  1. Have Unreal Engine 5.8.1 installed through Epic Games Launcher.
  2. Start the update to Unreal Engine 5.8.2.
  3. Allow the update to finish.
  4. Observe that Epic Games Launcher changes the engine state to “Resume”.
  5. Click Resume/Update again.
  6. The operation runs for only a few seconds, downloads no additional engine data, and returns to “Resume”.
  7. Check UnrealEditor.exe properties or Engine/Build/Build.version:
    • File version: 5.8.2.0
    • Product version: ++UE5+Release-5.8-CL-56702186
  8. Check the Launcher log. BuildPatch reports success, but the installation remains marked as incomplete and waits for a manifest commit.

Expected Result

After BuildPatch successfully completes the UE 5.8.2 update, Epic Games Launcher should commit the new installed manifest, clear the incomplete-install state, and display Unreal Engine 5.8.2 with the Launch button.

Observed Result

The Unreal Engine files are already UE 5.8.2 / CL 56702186, but Epic Games Launcher continues to report the previous 5.8.1 installation state and shows Resume.

Repeated Resume/Update attempts do not download additional data.

The log reports a successful BuildPatch operation, followed by:

IncompleteInstall=1 AutoResume=1

and:

completed, waiting for manifest commit before starting next download

The manifest commit does not complete.

A related warning appears immediately before this:

MainGameAppId mismatch detected for app UE_5.8
on-disk=ue:18b3b415bc434c5b974f50488360ca31:UE_5.8
catalog=(null):(null):(null)
Correcting to catalog value.

Affects Versions

5.8

Platform(s)

Windows

Upload an image

!

Additional Notes

Additional diagnostics:

The physical Unreal Engine installation was already fully updated to UE 5.8.2 / CL 56702186 before the Launcher UI was fixed.

The main UE 5.8 manifest matched the 5.8.2 build, and BuildPatch completed with:
ProcessSuccess: TRUE
ErrorCode: OK
FailureReasonText: The operation was successful.

The issue was isolated to the Launcher metadata/final manifest commit stage.

For diagnostic purposes, after backing up the original metadata and with Epic Games Launcher completely closed, I manually reconciled the installed UE_5.8 metadata to the already-installed 5.8.2 manifest and removed only the stale UE 5.8 pending transaction files.

After restarting Epic Games Launcher, it immediately displayed:
Unreal Engine 5.8.2
Launch

No additional Engine files had to be downloaded.

I have preserved the original installed .item, pending .item, manifests and Launcher logs if Epic needs them for investigation.

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.

:warning: Deprecated – use v2.0 instead

This older workaround is specific to UE 5.8.2 and has been superseded by the generic UE 5.8.x PowerShell diagnostic/workaround v2.0.

Please use v2.0 for UE 5.8.2, 5.8.3 and later 5.8.x hotfixes.

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.

Thanks for the share and getting down and dirty on the technicals. Just so you’re aware, this same behavior was kicking in with 5.8.2 → 5.8.3. Multiple update loops, couldn’t update plugins, etc. I tried several “fixes” to no avail, and was about to modify what you shared - but then magically seem to wake up and smell the roses.

Epic really needs to pin this down and squash this and related bugs ASAP. It’s affecting many people, it’s not a fringe issue. It seems to be loosely related to plugin update notification issues as well, where there are no actual updates to plugins, but launcher says there is. Or when users click on update, and nothing happens.

Thanks for the report, we have a ticket in.

Update: reproduced again with UE 5.8.3

I have now reproduced the same issue again while updating from UE 5.8.2 to UE 5.8.3.

Before starting the update, the installation was fully healthy:

Launcher metadata:      5.8.2-56702186
UnrealEditor.exe:       5.8.2.0 / CL-56702186
Build.version:          5.8.2 / CL-56702186
Pending item:           none
Pending manifest:       none

I then clicked Update once. The update downloaded and completed, but Epic Games Launcher returned to:

Unreal Engine 5.8.2
Resume

However, the physical Engine files were already updated successfully:

UnrealEditor.exe:
Numeric version: 5.8.3.0
ProductVersion: ++UE5+Release-5.8-CL-58210709

Engine\Build\Build.version:
Version: 5.8.3
Changelist: 58210709

Launcher metadata remained on:

5.8.2-56702186+++UE5+Release-5.8-Windows

while a new Pending transaction was created for:

5.8.3-58210709+++UE5+Release-5.8-Windows
bIsIncompleteInstall=True

The log shows the expected transition:

5.8.2-56702186 -> 5.8.3-58210709
Action: Update

and:

CurrentManifest: 5.8.2-56702186
InstallManifest: 5.8.3-58210709

BuildPatch then completes successfully:

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

but immediately afterwards:

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

So this appears to reproduce the same manifest-commit failure on the next hotfix, not just the original 5.8.1 → 5.8.2 update.

One additional finding: the earlier 5.8.2 reproduction logged:

MainGameAppId mismatch
catalog=(null):(null):(null)
Correcting to catalog value

In the 5.8.3 reproduction this has changed to:

MainGameAppId mismatch
catalog=(empty)
Keeping on-disk value

Despite that changed handling, the manifest commit still fails. This suggests the MainGameAppId warning may not be the primary cause of the Resume loop.

I have preserved the complete 5.8.3 Pending .item, Pending manifest, installed manifest, Launcher metadata and Launcher log for the existing ticket.

Update: v2.0 generic UE 5.8.x workaround confirmed on 5.8.3

I have now reproduced the same Launcher manifest-commit failure again while updating from UE 5.8.2 to UE 5.8.3.

The first Update successfully installed the physical Engine files:

UnrealEditor.exe:
5.8.3.0
++UE5+Release-5.8-CL-58210709

Engine\Build\Build.version:
5.8.3
CL 58210709

but Epic Games Launcher remained on:

UE 5.8.2
Resume

with a new Pending transaction for:

5.8.3-58210709+++UE5+Release-5.8-Windows
bIsIncompleteInstall=True

I therefore updated the workaround script to v2.0.

What changed in v2.0

v2.0 no longer hardcodes a specific hotfix such as 5.8.2 or 5.8.3.

Instead, it:

  • detects the target UE 5.8.x version automatically from the active Pending transaction,
  • extracts the target patch version and changelist,
  • verifies that target independently against UnrealEditor.exe,
  • verifies it again against Engine\Build\Build.version,
  • checks LauncherInstalled.dat,
  • checks both installed and Pending manifests,
  • simulates the metadata commit in memory first,
  • runs in DRY-RUN / READ-ONLY mode by default,
  • creates a full backup before Apply mode,
  • requires explicit APPLY confirmation,
  • promotes the Pending manifest only after all validations pass,
  • updates only the UE 5.8-specific metadata,
  • removes only the matching UE 5.8 Pending transaction,
  • verifies the final manifest SHA256.

Validation

v2.0 was tested end-to-end on this real UE 5.8.2 → 5.8.3 failure.

Before Apply:

Installed metadata:
  5.8.2-56702186

Physical Engine:
  5.8.3 / CL 58210709

Pending target:
  5.8.3-58210709

LauncherInstalled.dat:
  5.8.2-56702186

DRY-RUN result:

STATUS: AFFECTED / CONDITIONS MATCH
Target verification: MATCH
In-memory commit simulation: PASSED
DRY RUN PASSED

Apply result:

WORKAROUND COMPLETED SUCCESSFULLY

Committed Engine:
  UE 5.8.3 / CL 58210709

Installed metadata:
  5.8.3-58210709+++UE5+Release-5.8-Windows

Incomplete:
  False

LauncherInstalled.dat:
  5.8.3-58210709+++UE5+Release-5.8-Windows

Pending item exists:
  False

Pending manifest exists:
  False

Final manifest verification:

Installed manifest SHA256:
65619BCDBC675EC4CE4C9D349B7CAAA7DA3F281A2085A2D0070533C0893BD06A

Target Pending manifest SHA256:
65619BCDBC675EC4CE4C9D349B7CAAA7DA3F281A2085A2D0070533C0893BD06A

After restarting Epic Games Launcher, it correctly displayed:

Unreal Engine 5.8.3
Launch

No additional Engine download was required.

Important

This is still an unofficial workaround, not an Epic fix.

The script is deliberately read-only by default:

$ApplyChanges = $false

Only change it to $true if DRY-RUN confirms that the physical Engine already matches the Pending target exactly.

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


    # ============================================================
    # UE 5.8.x LAUNCHER MANIFEST DIAGNOSTIC / WORKAROUND
    # Version 2.0
    # ============================================================
    #
    # DEFAULT = SAFE / READ-ONLY
    #
    # Leave this as $false first.
    #
    # Change to $true ONLY after DRY RUN PASSED and only if the
    # system matches the manifest-commit issue described here.
    #
    # This version automatically detects the target UE 5.8.x
    # hotfix and changelist from the Pending transaction.
    #
    # ============================================================

    $ApplyChanges = $false


    # ============================================================
    # SUPPORTED ENGINE BRANCH
    # ============================================================

    $SupportedMajor = 5
    $SupportedMinor = 8
    $ExpectedAppName = "UE_5.8"


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

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

    $PendingRoot =
        Join-Path $ManifestRoot "Pending"

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


    # ============================================================
    # HELPERS
    # ============================================================

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

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


    function Parse-UeAppVersion {
        param(
            [Parameter(Mandatory = $true)]
            [string]$VersionString
        )

        #
        # Example:
        #
        # 5.8.3-58210709+++UE5+Release-5.8-Windows
        #

        $Pattern =
            '^(?<Major>\d+)\.(?<Minor>\d+)\.(?<Patch>\d+)-(?<CL>\d+)\+\+\+UE5\+Release-(?<BranchMajor>\d+)\.(?<BranchMinor>\d+)-Windows$'

        $Match =
            [regex]::Match(
                $VersionString,
                $Pattern
            )

        if (-not $Match.Success) {
            throw "STOP: Unsupported AppVersionString format: $VersionString"
        }

        [PSCustomObject]@{
            Raw         = $VersionString
            Major       = [int]$Match.Groups["Major"].Value
            Minor       = [int]$Match.Groups["Minor"].Value
            Patch       = [int]$Match.Groups["Patch"].Value
            CL          = [int64]$Match.Groups["CL"].Value
            BranchMajor = [int]$Match.Groups["BranchMajor"].Value
            BranchMinor = [int]$Match.Groups["BranchMinor"].Value
        }
    }


    function Get-SemVersion {
        param($Parsed)

        [version](
            "{0}.{1}.{2}" -f `
            $Parsed.Major,
            $Parsed.Minor,
            $Parsed.Patch
        )
    }


    Write-Host ""
    Write-Host "================================================"
    Write-Host " UE 5.8.x LAUNCHER MANIFEST DIAGNOSTIC v2.0"
    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 -LiteralPath $ManifestRoot)) {
        throw "STOP: Epic Games Launcher manifest directory was not found."
    }

    $MainCandidates = @()

    foreach (
        $File in
        Get-ChildItem `
            -LiteralPath $ManifestRoot `
            -Filter "*.item" `
            -File
    ) {
        try {
            $Data =
                Read-JsonFile $File.FullName

            if ($Data.AppName -eq $ExpectedAppName) {
                $MainCandidates +=
                    [PSCustomObject]@{
                        Path = $File.FullName
                        Data = $Data
                    }
            }
        }
        catch {
        }
    }


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


    $MainItemPath =
        $MainCandidates[0].Path

    $Main =
        $MainCandidates[0].Data


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


    $InstalledVersion =
        Parse-UeAppVersion $Main.AppVersionString


    if (
        $InstalledVersion.Major -ne $SupportedMajor -or
        $InstalledVersion.Minor -ne $SupportedMinor -or
        $InstalledVersion.BranchMajor -ne $SupportedMajor -or
        $InstalledVersion.BranchMinor -ne $SupportedMinor
    ) {
        throw "STOP: Installed metadata is not UE $SupportedMajor.$SupportedMinor.x."
    }


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


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

    $PendingCandidates = @()

    if (Test-Path -LiteralPath $PendingRoot) {

        foreach (
            $File in
            Get-ChildItem `
                -LiteralPath $PendingRoot `
                -Filter "*.item" `
                -File `
                -ErrorAction SilentlyContinue
        ) {
            try {
                $Data =
                    Read-JsonFile $File.FullName

                if ($Data.AppName -eq $ExpectedAppName) {
                    $PendingCandidates +=
                        [PSCustomObject]@{
                            Path = $File.FullName
                            Data = $Data
                        }
                }
            }
            catch {
            }
        }
    }


    # ============================================================
    # 3. VERIFY PHYSICAL ENGINE
    # ============================================================

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


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

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


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

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


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

    $Build =
        Read-JsonFile $BuildVersionPath


    $PhysicalVersion =
        [version](
            "{0}.{1}.{2}" -f `
            $VI.FileMajorPart,
            $VI.FileMinorPart,
            $VI.FileBuildPart
        )


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


    Write-Host ""
    Write-Host "[2] Physical Unreal Engine"
    Write-Host "Numeric FileVersion : $NumericFileVersion"
    Write-Host "FileVersion string  : $($VI.FileVersion)"
    Write-Host "ProductVersion      : $($VI.ProductVersion)"
    Write-Host "Build.version       : $($Build.MajorVersion).$($Build.MinorVersion).$($Build.PatchVersion)"
    Write-Host "Build CL            : $($Build.Changelist)"


    if (
        $VI.FileMajorPart -ne $SupportedMajor -or
        $VI.FileMinorPart -ne $SupportedMinor
    ) {
        throw "STOP: Physical Engine is not UE $SupportedMajor.$SupportedMinor.x."
    }


    if (
        $Build.MajorVersion -ne $VI.FileMajorPart -or
        $Build.MinorVersion -ne $VI.FileMinorPart -or
        $Build.PatchVersion -ne $VI.FileBuildPart
    ) {
        throw "STOP: UnrealEditor.exe and Build.version disagree about the Engine version."
    }


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

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


    if (-not (Test-Path -LiteralPath $Main.CompleteManifestPath)) {
        throw "STOP: Installed manifest was not found: $($Main.CompleteManifestPath)"
    }


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


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


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

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


    $Launcher =
        Read-JsonFile $LauncherDat


    $LauncherEntries = @(
        $Launcher.InstallationList |
        Where-Object {
            $_.AppName -eq $ExpectedAppName
        }
    )


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


    $LauncherUE58 =
        $LauncherEntries[0]


    $LauncherVersion =
        Parse-UeAppVersion $LauncherUE58.AppVersion


    Write-Host ""
    Write-Host "[4] LauncherInstalled.dat"
    Write-Host "Version : $($LauncherUE58.AppVersion)"


    # ============================================================
    # 6. ALREADY HEALTHY?
    # ============================================================

    if ($PendingCandidates.Count -eq 0) {

        $BuildSemVer =
            [version](
                "{0}.{1}.{2}" -f `
                $Build.MajorVersion,
                $Build.MinorVersion,
                $Build.PatchVersion
            )


        $InstalledSemVer =
            Get-SemVersion $InstalledVersion


        $LauncherSemVer =
            Get-SemVersion $LauncherVersion


        if (
            $InstalledSemVer -eq $BuildSemVer -and
            $LauncherSemVer -eq $BuildSemVer -and
            $Main.bIsIncompleteInstall -eq $false -and
            $InstalledVersion.CL -eq [int64]$Build.Changelist -and
            $LauncherVersion.CL -eq [int64]$Build.Changelist
        ) {

            Write-Host ""
            Write-Host "================================================"
            Write-Host " STATUS: ALREADY HEALTHY"
            Write-Host "================================================"
            Write-Host "Physical Engine and Launcher metadata agree:"
            Write-Host (
                "UE {0}.{1}.{2} / CL {3}" -f `
                $Build.MajorVersion,
                $Build.MinorVersion,
                $Build.PatchVersion,
                $Build.Changelist
            )
            Write-Host ""
            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: PHYSICAL ENGINE / METADATA MISMATCH"
        Write-Host "================================================"
        Write-Host "Physical Engine is newer or different from"
        Write-Host "Launcher metadata, but no Pending transaction"
        Write-Host "is currently available."
        Write-Host ""
        Write-Host "No changes were made."
        Write-Host ""
        Write-Host "If Launcher is showing Update/Resume, start"
        Write-Host "that operation once and run this script again"
        Write-Host "while the Pending transaction still exists."
        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


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


    $Target =
        Parse-UeAppVersion $Pending.AppVersionString


    Write-Host ""
    Write-Host "[5] Active Pending transaction"
    Write-Host "Item       : $PendingItemPath"
    Write-Host "Version    : $($Pending.AppVersionString)"
    Write-Host "Target     : $($Target.Major).$($Target.Minor).$($Target.Patch)"
    Write-Host "Target CL  : $($Target.CL)"
    Write-Host "Incomplete : $($Pending.bIsIncompleteInstall)"
    Write-Host "PrereqSHA1 : $($Pending.PrereqSHA1Hash)"


    # ============================================================
    # 7. VALIDATE TARGET BRANCH
    # ============================================================

    if (
        $Target.Major -ne $SupportedMajor -or
        $Target.Minor -ne $SupportedMinor -or
        $Target.BranchMajor -ne $SupportedMajor -or
        $Target.BranchMinor -ne $SupportedMinor
    ) {
        throw "STOP: Pending target is outside the supported UE 5.8.x branch."
    }


    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."
    }


    $InstalledSemVer =
        Get-SemVersion $InstalledVersion

    $TargetSemVer =
        Get-SemVersion $Target


    if ($InstalledSemVer -gt $TargetSemVer) {
        throw "STOP: Installed Launcher metadata is newer than the Pending target."
    }


    # ============================================================
    # 8. VERIFY TARGET AGAINST PHYSICAL ENGINE
    # ============================================================

    if ($PhysicalVersion -ne $TargetSemVer) {
        throw (
            "STOP: Physical UnrealEditor.exe version " +
            "$PhysicalVersion does not match Pending target $TargetSemVer."
        )
    }


    if (
        $Build.MajorVersion -ne $Target.Major -or
        $Build.MinorVersion -ne $Target.Minor -or
        $Build.PatchVersion -ne $Target.Patch -or
        [int64]$Build.Changelist -ne $Target.CL
    ) {
        throw "STOP: Build.version does not match the Pending target."
    }


    if ($VI.ProductVersion -notlike "*CL-$($Target.CL)*") {
        throw "STOP: UnrealEditor.exe ProductVersion does not match Pending target CL $($Target.CL)."
    }


    Write-Host ""
    Write-Host "[6] Target verification"
    Write-Host "Pending target     : $TargetSemVer / CL $($Target.CL)"
    Write-Host "UnrealEditor.exe   : $PhysicalVersion / CL $($Target.CL)"
    Write-Host "Build.version      : $($Build.MajorVersion).$($Build.MinorVersion).$($Build.PatchVersion) / CL $($Build.Changelist)"
    Write-Host "Result             : MATCH"


    # ============================================================
    # 9. 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 -LiteralPath $PendingManifestPath)) {
        throw "STOP: Pending manifest was not found: $PendingManifestPath"
    }


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


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


    # ============================================================
    # 10. VALIDATE LauncherInstalled.dat VERSION
    # ============================================================

    $LauncherSemVer =
        Get-SemVersion $LauncherVersion


    if ($LauncherSemVer -gt $TargetSemVer) {
        throw "STOP: LauncherInstalled.dat is newer than the Pending target."
    }


    if (
        $LauncherVersion.Major -ne $SupportedMajor -or
        $LauncherVersion.Minor -ne $SupportedMinor
    ) {
        throw "STOP: LauncherInstalled.dat is outside UE 5.8.x."
    }


    # ============================================================
    # 11. SIMULATE COMMIT IN MEMORY
    # ============================================================

    $SimMain =
        Read-JsonFile $MainItemPath


    $SimMain.AppVersionString =
        $Pending.AppVersionString

    $SimMain.PrereqSHA1Hash =
        $Pending.PrereqSHA1Hash

    $SimMain.bIsIncompleteInstall =
        $false


    $SimLauncher =
        Read-JsonFile $LauncherDat


    $SimLauncherEntries = @(
        $SimLauncher.InstallationList |
        Where-Object {
            $_.AppName -eq $ExpectedAppName
        }
    )


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


    $SimLauncherEntries[0].AppVersion =
        $Pending.AppVersionString


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

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


    $ParsedMain =
        $SimMainJson |
        ConvertFrom-Json

    $ParsedLauncher =
        $SimLauncherJson |
        ConvertFrom-Json


    $ParsedEntries = @(
        $ParsedLauncher.InstallationList |
        Where-Object {
            $_.AppName -eq $ExpectedAppName
        }
    )


    if ($ParsedMain.AppVersionString -ne $Pending.AppVersionString) {
        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 (
        $ParsedEntries.Count -ne 1 -or
        $ParsedEntries[0].AppVersion -ne $Pending.AppVersionString
    ) {
        throw "STOP: LauncherInstalled.dat simulation failed."
    }


    # ============================================================
    # DIAGNOSTIC RESULT
    # ============================================================

    Write-Host ""
    Write-Host "================================================"
    Write-Host " STATUS: AFFECTED / CONDITIONS MATCH"
    Write-Host "================================================"
    Write-Host ""
    Write-Host "Launcher installed metadata:"
    Write-Host "  $($Main.AppVersionString)"
    Write-Host ""
    Write-Host "Physical Engine:"
    Write-Host "  UE $TargetSemVer / CL $($Target.CL)"
    Write-Host ""
    Write-Host "Pending target:"
    Write-Host "  $($Pending.AppVersionString)"
    Write-Host ""
    Write-Host "LauncherInstalled.dat:"
    Write-Host "  $($LauncherUE58.AppVersion)"
    Write-Host ""
    Write-Host "Installed manifest SHA256:"
    Write-Host "  $InstalledManifestHash"
    Write-Host ""
    Write-Host "Pending manifest SHA256:"
    Write-Host "  $PendingManifestHash"
    Write-Host ""
    Write-Host "In-memory commit simulation:"
    Write-Host "  PASSED"


    # ============================================================
    # DRY RUN STOP
    # ============================================================

    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 "Detected target:"
        Write-Host "  UE $TargetSemVer / CL $($Target.CL)"
        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 the"
        Write-Host "Launcher still shows the failed Resume state."
        Write-Host "================================================"

        return
    }


    # ============================================================
    # APPLY MODE - CREATE BACKUP FIRST
    # ============================================================

    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_ManifestFix_{0}_{1}" -f `
                $TargetSemVer.ToString(),
                $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


    # ============================================================
    # USER CONFIRMATION / CLOSE LAUNCHER
    # ============================================================

    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 the"
    Write-Host "Launcher exits. That is OK because they are"
    Write-Host "already preserved 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 ""
        Write-Host "Backup was kept:"
        Write-Host $BackupDir

        return
    }


    # ============================================================
    # VERIFY LAUNCHER IS 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-VALIDATE PHYSICAL ENGINE AFTER LAUNCHER SHUTDOWN
    # ============================================================

    $PostBuild =
        Read-JsonFile $BuildVersionPath


    if (
        $PostBuild.MajorVersion -ne $Target.Major -or
        $PostBuild.MinorVersion -ne $Target.Minor -or
        $PostBuild.PatchVersion -ne $Target.Patch -or
        [int64]$PostBuild.Changelist -ne $Target.CL
    ) {
        throw "STOP: Physical Engine changed after backup. No commit 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 $Pending.AppVersionString) {
        throw "STOP: Backup Pending version does not match detected target."
    }


    if ($BackupPending.PrereqSHA1Hash -ne $Pending.PrereqSHA1Hash) {
        throw "STOP: Backup Pending PrereqSHA1Hash mismatch."
    }


    # ============================================================
    # 12. PROMOTE PENDING MANIFEST
    # ============================================================

    $BackupPendingManifest =
        Join-Path $BackupDir "pending.manifest"


    $BackupPendingHash =
        (Get-FileHash `
            -LiteralPath $BackupPendingManifest `
            -Algorithm SHA256).Hash


    if ($BackupPendingHash -ne $PendingManifestHash) {
        throw "STOP: Pending manifest backup hash mismatch."
    }


    Copy-Item `
        -LiteralPath $BackupPendingManifest `
        -Destination $BackupMain.CompleteManifestPath `
        -Force


    # ============================================================
    # 13. COMMIT INSTALLED ITEM METADATA
    # ============================================================

    #
    # Keep the installed item's structure/options.
    # Promote only fields known to belong to the completed build.
    #

    $BackupMain.AppVersionString =
        $BackupPending.AppVersionString

    $BackupMain.PrereqSHA1Hash =
        $BackupPending.PrereqSHA1Hash

    $BackupMain.bIsIncompleteInstall =
        $false


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


    [IO.File]::WriteAllText(
        $MainItemPath,
        ($BackupMain | ConvertTo-Json -Depth 20),
        $Utf8NoBom
    )


    # ============================================================
    # 14. UPDATE LauncherInstalled.dat
    # ============================================================

    #
    # Read the current file after Launcher shutdown so unrelated
    # application entries are preserved.
    #

    $CurrentLauncher =
        Read-JsonFile $LauncherDat


    $CurrentEntries = @(
        $CurrentLauncher.InstallationList |
        Where-Object {
            $_.AppName -eq $ExpectedAppName
        }
    )


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


    $CurrentEntries[0].AppVersion =
        $BackupPending.AppVersionString


    [IO.File]::WriteAllText(
        $LauncherDat,
        ($CurrentLauncher | ConvertTo-Json -Depth 20),
        $Utf8NoBom
    )


    # ============================================================
    # 15. REMOVE ONLY THIS UE_5.8 PENDING TRANSACTION
    # ============================================================

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


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


    # ============================================================
    # 16. FINAL VERIFICATION
    # ============================================================

    $FinalMain =
        Read-JsonFile $MainItemPath


    $FinalLauncher =
        Read-JsonFile $LauncherDat


    $FinalEntries = @(
        $FinalLauncher.InstallationList |
        Where-Object {
            $_.AppName -eq $ExpectedAppName
        }
    )


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


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


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


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


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


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


    if (Test-Path -LiteralPath $PendingItemPath) {
        throw "FINAL VERIFY FAILED: Pending item still exists."
    }


    if (Test-Path -LiteralPath $PendingManifestPath) {
        throw "FINAL VERIFY FAILED: Pending manifest still exists."
    }


    Write-Host ""
    Write-Host "================================================"
    Write-Host " WORKAROUND COMPLETED SUCCESSFULLY"
    Write-Host "================================================"
    Write-Host ""
    Write-Host "Committed Engine:"
    Write-Host "  UE $TargetSemVer / CL $($Target.CL)"
    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 "  $($FinalEntries[0].AppVersion)"
    Write-Host ""
    Write-Host "Installed manifest SHA256:"
    Write-Host "  $FinalInstalledManifestHash"
    Write-Host ""
    Write-Host "Target manifest SHA256:"
    Write-Host "  $BackupPendingHash"
    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 "Backup:"
    Write-Host "  $BackupDir"
    Write-Host ""
    Write-Host "You can now start Epic Games Launcher."
    Write-Host "================================================"
}

UE-398557 has been ‘Closed’ as a duplicate of an existing known issue.

Hi @Flak,
Bug-Reporter has now marked UE-398557 as “Closed” because it is a duplicate of an existing known issue.
Could you please share the ID or public Issues Tracker link for the parent/original issue?
I’d like to reference the correct ticket in this thread and track the actual fix/status.
Thanks!

this engine is “industry standard”… ? what a sad industry

I have the same issue trying to update from UE 5.8.2 to 5.8.3

The difference is, Epic Downloader will download about 5GB of data every time I “Resume” the operation (of updating UE 5.8.2)

It ultimately remains stuck at “Resume” in Epic Launcher.

Sometimes I can then Launch UE, but my roster of project templates has disappeared and I can only start a blank project.

I checked the UE program files, and indeed the files are at 5.8.3. in fact Engine/Build/Build.version reads as: {“MajorVersion”: 5,“MinorVersion”: 8,“PatchVersion”: 3,“Changelist”: 58210709,“CompatibleChangelist”: 55116800,“IsLicenseeVersion”: 0,“IsPromotedBuild”: 1,“BranchName”: “++UE5+Release-5.8”}

I tried several times the Resume action. Next I will try to uninstall UE 5.8.2 and reinstall.

Hi @HYP_mli,

based on what you posted, I would not uninstall/reinstall UE 5.8 yet.

Your Engine/Build/Build.version already reports:

UE 5.8.3
CL 58210709

so the physical Engine files appear to have already been updated successfully.

That is the same pattern I reproduced:

Physical Engine:    UE 5.8.3
Launcher metadata:  previous version
Launcher state:     Resume

In other words, the Engine itself is already updated, but Epic Games Launcher appears to be stuck during the final manifest / metadata commit.

A reinstall may therefore be unnecessary and could simply recreate the same Launcher-side problem.

Before uninstalling anything, I would suggest running the v2.0 PowerShell diagnostic I posted above with:

$ApplyChanges = $false

This is the default read-only DRY-RUN mode.

It does not modify, delete or replace any files.

If your installation matches the same issue, it should report something similar to:

STATUS: AFFECTED / CONDITIONS MATCH

Target verification:
MATCH

In-memory commit simulation:
PASSED

DRY RUN PASSED

If you get that result, then your installation matches the same manifest-commit issue.

Only after that, if you want to apply the workaround, you can change:

$ApplyChanges = $false

to:

$ApplyChanges = $true

The Apply mode creates a complete backup before changing anything and requires explicit confirmation by typing:

APPLY

I tested v2.0 end-to-end on a real UE 5.8.2 → 5.8.3 failure.

After the workaround, Epic Games Launcher immediately changed from:

UE 5.8.2
Resume

to:

UE 5.8.3
Launch

without downloading the Engine again.

I would recommend running the DRY-RUN before uninstalling, because the current Pending transaction is useful for diagnosing and repairing this exact state.

The missing project templates may also be another symptom of the Launcher being left in an incomplete/stale application state, although I cannot confirm yet that it has exactly the same root cause.

Yes, you were right. The uninstall/reinstall didn’t help at all. I ended up using your PowerShell script which solved the issue. Many thanks!

Glad it worked for you, and thanks for confirming it.

Your result is actually very useful because it confirms that reinstalling the Engine does not necessarily fix the problem, while the manifest-state workaround does.

Hopefully this helps Epic narrow down the root cause as well.

Thanks for the detailed investigation and workaround. I encountered a very similar issue with a fresh installation of UE 5.8.3, but with one important difference.

Using Epic Games Launcher 20.3.5 on Windows 11, installation reached 100%, then failed with IS-EO-ih_early_exit. The Launcher remained stuck on Resume. Uninstalling and reinstalling didn’t help.

After digging through the logs with ChatGPT:

  • BuildPatch successfully installed and verified all 250,504 files (ProcessSuccess: TRUE, ErrorCode: OK).

  • Immediately afterward, InstallHelper stalled for approximately 30 seconds (HB-Timeout, step=RunBps).

  • UE 5.8.3 / CL 58210709 was physically installed and could launch directly through UnrealEditor.exe.

  • Unlike your update scenario, there was no completed UE 5.8 .item or LauncherInstalled.dat registration. Only pending installation records existed, with the .egi state marked Incomplete.

Your v2 workaround helped identify the problem, but it expects an existing installation record, which my fresh installation didn’t have.

I had ChatGPT build a modified PowerShell repair script that promoted the pending manifest, finalized the .item and .egi records, and registered UE 5.8.3 in LauncherInstalled.dat.

This modified script worked. My Epic Games Launcher now recognizes UE 5.8.3 and launches the editor normally, without downloading the engine again.

I’ve also prepared a generalized version specifically for this fresh-install-fail scenario:

Powershell Repair Script and README

This script automatically discovers the installation ID, build, and paths. It runs read-only by default, with safety checks, backups, and explicit confirmation before applying changes.

Important: I have only tested my installation-specific repair script. The above linked generalized script hasn’t yet been tested at all. It was built by ChatGPT based off the successful installation-specific repair script. The above linked script should be considered an untested experimental workaround and isn’t intended for existing-installation updates.

Hopefully this provides another useful data point for Epic’s investigation. Thanks again for the groundwork.

Epic Games Launcher 20.3.5 recovery test + ProcMon analysis

After updating Epic Games Launcher to 20.3.5, I performed another controlled test.

This time I restored the exact metadata/manifest state captured from my original UE 5.8.2 → 5.8.3 failure, where the physical Engine files had already been successfully updated to 5.8.3, but the Launcher transaction had not been committed correctly.

Important test limitation

This was not a fresh 5.8.2 → 5.8.3 download/update.

The physical Engine installation was already:

UE 5.8.3
CL 58210709

I restored only the previously captured Launcher/manifest transaction state in order to test how Launcher 20.3.5 recovers from the exact historical failure state.

So this test does not yet prove that the original update bug is fully fixed during an actual future hotfix update.


Restored historical broken state

Before starting Launcher 20.3.5:

Physical Engine:
    UE 5.8.3 / CL58210709

installed.item:
    5.8.2-56702186+++UE5+Release-5.8-Windows
    bIsIncompleteInstall = False

pending.item:
    5.8.3-58210709+++UE5+Release-5.8-Windows
    bIsIncompleteInstall = True

installed.manifest SHA256:
    9CB3C546C7D3C8C111D6D8AD69FE090714F5304FF1F81E099BD95B9F7493C86D

pending.manifest SHA256:
    65619BCDBC675EC4CE4C9D349B7CAAA7DA3F281A2085A2D0070533C0893BD06A

LauncherInstalled.dat:
    5.8.2-56702186+++UE5+Release-5.8-Windows

This reproduces the transaction state that previously resulted in Resume.


What Launcher 20.3.5 did

After the first startup, Launcher 20.3.5 did not show Resume.

Instead, the UI showed:

UE 5.8.3
Launch

The installed .item was rebuilt/promoted to:

AppVersionString:
    5.8.3-58210709+++UE5+Release-5.8-Windows

bIsIncompleteInstall:
    False

PrereqSHA1Hash:
    932A2A14C03E1FDA5B9FBF8200290E8FE9CC9F1A

The previous pending.item was removed.

Several properties in the new installed .item matched the historical pending.item, including:

ManifestHash
InstallTags
MainGameAppName
MainGameCatalogItemId
MainGameCatalogNamespace
BaseURLs

For example:

pending.item ManifestHash:
    6edc11fbb1bfac1c45580b1e0d9dee50f8c8b827

new installed.item ManifestHash:
    6edc11fbb1bfac1c45580b1e0d9dee50f8c8b827

This strongly suggests that Launcher 20.3.5 now performs an item-level recovery/promotion from the incomplete pending state.


However, the manifest transaction was still not completed

After the first recovery stage:

installed.item:
    5.8.3 / incomplete=False       OK

pending.item:
    removed                        OK

Launcher UI:
    5.8.3 / Launch                 OK

but the underlying manifest storage was still:

installed.manifest:
    old 5.8.2 manifest
    SHA256 = 9CB3C546C7D3C8C111D6D8AD69FE090714F5304FF1F81E099BD95B9F7493C86D

pending.manifest:
    still present
    SHA256 = 65619BCDBC675EC4CE4C9D349B7CAAA7DA3F281A2085A2D0070533C0893BD06A

Initially, LauncherInstalled.dat also remained at 5.8.2.

On a subsequent Launcher startup it was updated to:

LauncherInstalled.dat:
    5.8.3-58210709+++UE5+Release-5.8-Windows

but the manifest files still remained unchanged.

I repeated the startup again.

After Startup #3:

installed.item        = 5.8.3 / incomplete=False
pending.item          = missing
LauncherInstalled.dat = 5.8.3

installed.manifest    = old 5.8.2 manifest
pending.manifest      = still present 5.8.3 manifest

So the remaining manifest state was stable across additional Launcher restarts.


Process Monitor result

I captured Startup #3 using Sysinternals Process Monitor.

This is the most interesting part of the test.

For the installed manifest:

G:\Epic_Games\UE_5.8\.egstore\
D1AC6C594CBE88D6B55411CFA033E4CE.manifest

Launcher opened and read the existing old manifest successfully:

16:01:07.529  CreateFile  Generic Read    SUCCESS
16:01:07.536  ReadFile    36,373,780 B    SUCCESS
16:01:07.552  CloseFile                  SUCCESS

However, during the entire captured startup there were zero accesses to:

G:\Epic_Games\UE_5.8\.egstore\Pending\
D1AC6C594CBE88D6B55411CFA033E4CE.manifest

No operations of the following types were observed against the pending manifest:

CreateFile
WriteFile
SetRenameInformationFile
SetDispositionInformationFile

In other words, Launcher did not attempt to promote the pending manifest at all during this recovery startup.

There were also no relevant filesystem errors such as:

ACCESS DENIED
SHARING VIOLATION
PATH NOT FOUND
NAME NOT FOUND

All file operations for the UE 5.8 manifest GUID that were present in the captured trace completed with SUCCESS.

So at least in this recovery path, this does not look like Windows refusing a manifest rename/write operation.

Instead, Launcher appears not to enter the code path that would complete the pending-manifest promotion.


The .item is still actively rewritten

ProcMon shows that Launcher 20.3.5 actively rewrites the installed .item:

16:01:04.713  ReadFile
16:01:08.021  CreateFile / OverwriteIf   SUCCESS
16:01:08.021  WriteFile  2,665 B         SUCCESS
16:01:08.021  CloseFile                  SUCCESS

LauncherInstalled.dat was also successfully rewritten:

16:01:04.808  CreateFile / OverwriteIf   SUCCESS
16:01:04.809  WriteFile  7,062 B         SUCCESS
16:01:04.809  CloseFile                  SUCCESS

So there is no evidence in this trace that file permissions were the limiting factor.


Current interpretation

Launcher 20.3.5 appears to have improved recovery from this stale transaction state:

pending.item
      ↓
installed.item 5.8.3
bIsIncompleteInstall=False
      ↓
pending.item removed
      ↓
LauncherInstalled.dat eventually updated to 5.8.3
      ↓
UI shows Launch

But the final manifest transaction remains incomplete:

installed.manifest = old 5.8.2 manifest
pending.manifest   = new 5.8.3 manifest

On later startups Launcher reads the old installed manifest while apparently ignoring the still-existing pending manifest.

So my current conclusion is:

Epic Games Launcher 20.3.5 improves recovery of the visible/install-metadata state, but in this controlled replay it still does not complete the pending-manifest promotion.

This is important because the UI can now show 5.8.3 / Launch even while the underlying manifest storage remains internally inconsistent.

It also suggests that the original issue is probably not simply a filesystem permission or file-locking problem.

At least in this reproduced recovery state, the remaining pending manifest does not appear to be blocked during promotion — no promotion attempt is visible in the captured trace at all.


Final verification

After completing the test, I restored the known-good state:

installed.item:
    5.8.3-58210709+++UE5+Release-5.8-Windows
    bIsIncompleteInstall = False

installed.manifest SHA256:
    65619BCDBC675EC4CE4C9D349B7CAAA7DA3F281A2085A2D0070533C0893BD06A

pending.item:
    absent

pending.manifest:
    absent

LauncherInstalled.dat:
    5.8.3-58210709+++UE5+Release-5.8-Windows

Physical Engine:
    UE 5.8.3 / CL58210709

I then launched UE 5.8.3 normally and confirmed that the Engine starts correctly.

So the physical Engine installation itself remains valid.


Current recommendation

If Epic Games Launcher 20.3.5 completes a UE 5.8.x update normally, does not fall back into an Update → Resume loop, the Engine launches normally, and the state remains stable across subsequent Launcher restarts, no workaround should normally be necessary.

The v2.0 workaround should only be considered if the original symptoms return, for example:

  • the update finishes but the Launcher remains on Resume
  • the Launcher repeatedly offers Update
  • the physical Engine files are already on the target version, but the Launcher still reports an older/incomplete state

In that situation, the v2.0 script can first be run in its default read-only DRY-RUN mode to determine whether the installation matches the same manifest-commit failure before making any changes.

A full uninstall/reinstall should not be the first troubleshooting step, since another affected user already confirmed that reinstalling did not resolve the issue, while the manifest-state workaround did.

The definitive test will be the next real UE 5.8.x hotfix update under Launcher 20.3.5.

That will determine whether the original failure in the actual update/commit path has been fixed, or whether Launcher 20.3.5 has only improved recovery from an already broken transaction state.

Thanks, Kyle — this is a very useful additional data point.

The distinction you found is especially interesting because your failure happens during a fresh UE 5.8.3 installation, while my reproduced cases were updates of an already registered UE 5.8 installation.

In my case, BuildPatch also completed successfully and the physical Engine was already valid, but an older installed .item, manifest and LauncherInstalled.dat entry still existed.

Your case appears to fail one stage earlier:

BuildPatch succeeds
        ↓
physical UE 5.8.3 installation is valid
        ↓
InstallHelper / post-install finalization fails
        ↓
only pending records remain
        ↓
no completed installed registration
        ↓
Launcher stays on Resume

Controlled fresh-install comparison with Kyle G’s report

After Kyle G reported a fresh UE 5.8.3 installation failing at 100% with:

IS-EO-ih_early_exit

followed by the Launcher getting stuck on Resume, I performed a controlled fresh-install test on my own system using Epic Games Launcher 20.3.5.

Before starting the test, I removed all known UE 5.8 installation registration state while preserving my existing working Engine installation separately.

An important detail discovered during this preparation was that Epic also keeps installation state here:

C:\ProgramData\Epic\EpicOnlineServicesShared\InstallHelper\InstalledItems\

The old UE 5.8 installation still had:

D1AC6C594CBE88D6B55411CFA033E4CE.egi

with:

state = Installed

and:

dir = G:\Epic_Games\UE_5.8

Even after the normal .item record and the UE 5.8 entry in LauncherInstalled.dat had been removed, this .egi record caused the Launcher to reconstruct a new .item and display Repair instead of Install.

ProcMon showed the sequence clearly:

EpicOnlineServicesInstallHelper.exe
reads the existing .egi

→

EpicGamesLauncher.exe
does not find the normal .item

→

the Launcher creates a reconstructed .item

→

the Launcher repeatedly checks the old:

G:\Epic_Games\UE_5.8\.egstore\...manifest

which no longer exists

→

the UI shows Repair

After moving both the old .egi and the reconstructed .item out of the live state, with no UE 5.8 entry in LauncherInstalled.dat and no Engine present at the old install path, the Launcher finally showed:

Not Installed

and:

Install

This gave me a genuine fresh-install baseline.

I then installed UE 5.8.3 to a new location on another drive:

H:\Epic_Games\UE_5.8_FreshTest\UE_5.8

using the same component selection I normally use:

  • Core Components
  • Templates and Feature Packs
  • Engine Source

The fresh installation completed normally.

Final result:

100% → Launch

There was no:

IS-EO-ih_early_exit

and no:

Resume

The Engine also launched successfully afterwards.

The new installation received a new installation ID:

AE781EAC3329F9BD72C636D27920C5D

and the final physical state was consistent:

UE 5.8.3-58210709+++UE5+Release-5.8-Windows

Build.version: 5.8.3

Changelist: 58210709

Installed manifest:

AE781EAC3329F9BD72C636D27920C5D.manifest

SHA256:

65619BCDBC675EC4CE4C9D349B7CAAA7DA3F281A2085A2D0070533C0893BD06A

No pending manifest remained.

The .egi state was:

Installed

and the .item had:

bIsIncompleteInstall = False

After restarting the Launcher, the UE 5.8 entry was also added to LauncherInstalled.dat, and the installation remained stable.

So, unlike Kyle G’s fresh-install case, I was not able to reproduce the IS-EO-ih_early_exit → Resume failure on Launcher 20.3.5.

This suggests that the fresh-install failure is not deterministic for every UE 5.8.3 installation under Launcher 20.3.5 and may depend on additional machine-specific or installation-state conditions.

It also shows that .egi records under EpicOnlineServicesShared\InstallHelper\InstalledItems are an important part of the Launcher’s persistent installation state and can cause an apparently removed Engine installation to be reconstructed as Repair.

Small diagnostic update — I now have a clean control case that succeeds.

I restored a fresh UE 5.8.3 installation on a separate drive and updated it to 5.8.4 using the same Epic Games Launcher 20.3.6.

The clean control update completed normally and ended in 5.8.4 / Launch.

The interesting part is the EOSH / InstallHelper sequence.

On the successful control install, EpicOnlineServicesInstallHelper receives an explicit:

type: install
ActionType: InstallOrUpdate
ArtifactId: UE_5.8

Before BuildPatch starts, InstallHelper:

  • downloads/copies the target 5.8.4 manifest into .egstore\Pending
  • writes the UE installation .egi in a pending/updating state
  • advances the EOSH revision

Then BuildPatch runs.

After BuildPatch succeeds, InstallHelper:

  • moves the pending 5.8.4 manifest to the installed manifest location
  • writes the .egi again with state=Installed
  • advances the revision again
  • completes the install task with Status=Success

In my successful control case the revisions were:

...0028 — pending/update state before BPS
...0029 — final Installed state after BPS

The original broken UE 5.8 installation behaves differently.

There, the physical engine files are already 5.8.4 and BuildPatch reports success, but the EOSH .egi remains on the old 5.8.3 registration and I have not observed the equivalent successful EOSH install transaction that occurs in the clean control case.

So the current failure boundary appears to be narrower than “BuildPatch fails” or “manifest download fails”:

BuildPatch can succeed, while the EOSH installation registration/commit state does not advance to the new UE version.

I am still testing two remaining differences before calling this the root cause:

  1. the broken installation had an editor_symbols Modify/TagChange operation involved before the 5.8.4 update
  2. that installation also has Fab / Quixel follower plugin tasks associated with the UE update

I’ll post the final comparison once those two cases are tested.

The goal of mapping the successful EOSH state transition this precisely is also practical: it should make it possible to build a safer Workaround v3 that repairs only the metadata state that can be validated from a known-good transaction, instead of guessing or fabricating EOSH revision/state data.

UE 5.8.x Resume Loop — Workaround v3.3: Stale ManifestHash (Possible Root Cause)

Final investigation update — October 30, 2026

Confirmed case: Unreal Engine 5.8.3 → 5.8.4
Platform: Windows 11
Result: The persistent Resume loop was resolved. Epic Games Launcher now displays Launch.

Important: This post describes a confirmed workaround for a specific installation state. The internal root cause has not been conclusively established and requires investigation by Epic. This should not be treated as a universal fix for every UE 5.8.x Resume loop.


1. Summary

After extensive investigation of a persistent Resume loop in Epic Games Launcher (EGL), I was finally able to narrow the issue down to one particular metadata field:

ManifestHash

Earlier troubleshooting, including the v2 workaround, focused on recovering the installation from incomplete or inconsistent update states.

However, the problem kept returning.

The successful v3.3 experiment took a different approach.

Instead of modifying EOSH registration, revision counters, pending manifests, or plugin metadata, I cleared exactly one stale ManifestHash value in the live EGL .item file.

Before:

"ManifestHash": "7824ea53198b0f36a0a291bb3ee11f563912056d"

After:

"ManifestHash": ""

Following this change, Epic Games Launcher correctly prepared the EOSH pending transaction, completed the update from UE 5.8.3 to UE 5.8.4, and displayed Launch instead of returning to Resume.

No Unreal Engine binaries, EOSH revisions, installed manifests, or plugin registrations were manually modified.

This is the central finding of the investigation.


2. The original problem

The affected installation was registered as:

5.8.3-58210709+++UE5+Release-5.8-Windows

The intended update was:

5.8.4-58902052+++UE5+Release-5.8-Windows

Epic Games Launcher repeatedly attempted the update but eventually returned to Resume.

The observed failing update sequence was approximately:

UE 5.8.3 installed
        |
        v
EGL selects UE 5.8.4 update
        |
        v
CommunityPortalPatcher / BPS
        |
        v
Patch activity completes
        |
        v
EOSH remains Installed 5.8.3
        |
        v
EOSH pending remains empty
        |
        v
EGL returns to Resume

An important detail is that the logs did show a manifest commit callback.

Therefore, I would not describe the problem simply as a missing callback.

The more significant observation was that the expected EOSH pending → installed transaction did not occur.

The patching process and the registered installation state were not progressing together as expected.


3. What changed between workaround v2 and v3.3?

The earlier v2 approach concentrated on the consequences of the unsuccessful update.

It involved examining and recovering inconsistent installation states and leftover update artifacts.

That was useful for understanding the behavior, but it did not permanently resolve the recurring Resume loop in my installation.

The v3.3 investigation instead focused on identifying what might be triggering the incorrect update path.

The key difference was the live .item field:

ManifestHash

In the affected installation, the field contained a non-empty value even though the installation had been returned to a stable UE 5.8.3 state.

A separate successfully updated installation provided a useful comparison.

This led to the hypothesis that the stale hash might influence how EGL selects or prepares the update transaction.

Rather than changing multiple metadata sources, I tested this hypothesis by changing only that field.

The result was successful.


4. Original installation metadata

The affected installation used the following Installation ID:

D1AC6C594CBE88D6B55411CFA033E4CE

The corresponding EGL metadata file was:

C:\ProgramData\Epic\EpicGamesLauncher\Data\Manifests\
D1AC6C594CBE88D6B55411CFA033E4CE.item

The related EOSH installation record was located under:

C:\ProgramData\Epic\EpicOnlineServicesShared\
InstallHelper\InstalledItems\

Verified state before the successful patch

Metadata Value
EGL version UE 5.8.3
Incomplete installation False
ManifestHash 7824ea53198b0f36a0a291bb3ee11f563912056d
EOSH state Installed
EOSH current version UE 5.8.3
EOSH pending version Empty
EGL item revision 08DECBF173004248000000000000002E
EOSH revision 08DECBF173004248000000000000002E
Global revision 46
Active pending files None
Active BPS directory None

The original installed manifest SHA256 was:

65619BCDBC675EC4CE4C9D349B7CAAA7DA3F281A2085A2D0070533C0893BD06A

The expected target manifest SHA256 for UE 5.8.4 was:

4AEA3C5963D3C44B26EC4D8A9D62F492F5FDE13E5479D1D186CA946DBC1F692E

These fingerprints were used to distinguish the original stable installation from the intended target update.


5. The controlled one-field experiment

Before applying the patch, I verified that the installation was in a stable state.

The installed version and EOSH version agreed.

The .item and .egi revisions matched.

No active EOSH pending transaction, pending .item, pending manifest, or BPS operation remained.

The original metadata was backed up.

I then made the following change in the live EGL .item file:

- "ManifestHash": "7824ea53198b0f36a0a291bb3ee11f563912056d"
+ "ManifestHash": ""

The modification was byte-preserving apart from removing the 40-character hash value.

No other .item properties were modified.

SHA256 verification

Original .item:

86161597EB248A44F5D57C8B9FFA11EC0717562D1FBF2AFFB6DEB24773269F57

After the one-field patch:

86704755844536D28731F553CA93ADD779725D2E516E61D08CC2527427D693E4

The resulting file remained valid JSON.

Importantly, the following files and values were not manually modified:

  • EOSH .egi installation records
  • Revision.json
  • LauncherInstalled.dat
  • EoshRevision
  • Installed manifests
  • Unreal Engine binaries
  • Plugin registrations

After this single change, I restarted EGL and initiated the update.


6. Successful EOSH transaction

This time, the launcher followed a different and successful sequence.

Before Update

EOSH current  = 5.8.3
EOSH pending  = empty

EOSH revision = ...002E
Global        = 46

During Update

EOSH current  = 5.8.3
EOSH pending  = 5.8.4

EOSH revision = ...002F
Global        = 47

The pending target manifest matched the expected UE 5.8.4 SHA256:

4AEA3C5963D3C44B26EC4D8A9D62F492F5FDE13E5479D1D186CA946DBC1F692E

After Update

EOSH state    = Installed
EOSH current  = 5.8.4
EOSH pending  = empty

EOSH revision = ...0030
Global        = 48

EGL UI        = Launch

The completed installation also matched the expected target manifest SHA256.

The physical engine build reported:

CL 58902052

No active pending transaction or BPS artifacts remained.

The original Resume loop was resolved, and the existing plugin entries were preserved.

This confirmed that the one-field change was sufficient to unblock the update in my installation.


7. Possible root cause

Based on these observations, my current hypothesis is:

A stale, non-empty ManifestHash in the live EGL installation record may influence the update path selected by Epic Games Launcher, preventing the expected EOSH pending transaction from being prepared or completed.

The observed behavior supports the following possible sequence:

STALE ManifestHash
        |
        v
EGL selects update path
        |
        v
CommunityPortalPatcher / BPS
        |
        v
No corresponding EOSH pending transition
        |
        v
Resume loop

After clearing the field:

ManifestHash = ""
        |
        v
EGL Update
        |
        v
EOSH prepares pending 5.8.4
        |
        v
Patch / installation process
        |
        v
EOSH finalizes Installed 5.8.4
        |
        v
Launch

There is a strong experimental indication that this field was involved in triggering the failure.

However, I cannot confirm the internal EGL/EOSH decision logic.

I also cannot conclude that every non-empty ManifestHash is invalid or stale.

The exact root cause and appropriate permanent fix need to be established by Epic’s engineers.


8. Workaround v3.3 — final PowerShell script

After confirming the successful real-world update, I developed a simplified public workaround based directly on the one-field experiment.

Attachment:

UE58_ResumeFix_v3_3_Final.zip (4.6 KB)

Included script:

UE58_ResumeFix_v3_3_Final.ps1

SHA256 checksum (PowerShell script, not ZIP archive):

4CE95BACB6F807DF87C20E54FC8B3EE9B8F81AE5CC1C67C0686C79A192A0CF45

To verify the integrity of the extracted script, run:

Get-FileHash .\UE58_ResumeFix_v3_3_Final.ps1 -Algorithm SHA256

The resulting SHA256 hash should match the value above exactly.

If the checksum does not match, do not execute the script.

The script is provided as an unofficial community workaround. Please review its contents before running it.

The final version deliberately focuses on the original successful intervention rather than attempting to repair or manage every possible EGL/EOSH state.

Available modes

Audit

Performs read-only checks of the installed version, EOSH state, revisions, pending artifacts, ManifestHash, and installed manifest.

Apply

Creates backups and clears the specific stale ManifestHash, but only when the installation matches the confirmed fingerprint and passes the safety checks.

Verify

Confirms that the patched .item remains valid and that EOSH and installed-manifest metadata have not changed unexpectedly before starting the update.

Usage

Extract the ZIP and inspect the PowerShell script before executing it.

Open PowerShell in the directory containing the extracted .ps1 file.

Step 1 — Audit

.\UE58_ResumeFix_v3_3_Final.ps1 `
    -Mode Audit `
    -InstallRoot "G:\Epic_Games\UE_5.8"

Replace G:\Epic_Games\UE_5.8 with your actual installation path.

Only continue if the script reports:

READY_FOR_PATCH

If it reports one of the following, do not force the patch:

HEALTHY / NOT_APPLICABLE

UNTESTED_FINGERPRINT

UNSAFE_STATE

Step 2 — Apply

Completely close Epic Games Launcher and EpicWebHelper.

.\UE58_ResumeFix_v3_3_Final.ps1 `
    -Mode Apply `
    -InstallRoot "G:\Epic_Games\UE_5.8"

A successful operation should report:

ONE_FIELD_PATCH_APPLIED

The script also displays the backup directory.

Keep the backup.

Step 3 — Verify

Restart Epic Games Launcher, but do not click Update yet.

Run:

.\UE58_ResumeFix_v3_3_Final.ps1 `
    -Mode Verify `
    -InstallRoot "G:\Epic_Games\UE_5.8"

Only continue if the result is:

PATCH_ACCEPTED

You may then attempt the normal Update operation inside EGL.

If verification fails, stop and investigate the metadata state instead of repeatedly attempting modifications.

Important limitations

This workaround intentionally recognizes only the specific UE 5.8.3 state established during my investigation.

A different version, manifest fingerprint, or ManifestHash may cause the script to refuse the operation.

That is expected behavior.

The script does not attempt to clear arbitrary hashes, modify EOSH records, force revision changes, or manipulate active update transactions.

It also does not automatically restore metadata after a transaction has started.


9. Validation and negative testing

To validate the public workaround, I used an authentic snapshot of the original UE 5.8.3 metadata, preserved before the successful repair on October 29, 2026.

This included:

<InstallationID>.item.before
<InstallationID>.egi.before
Revision.json.before
LauncherInstalled.dat.before
state.json

The snapshot confirmed the original UE 5.8.3 version, the stale hash, matching EOSH revisions, and the empty pending state.

I then tested the actual Apply and Verify logic from the simplified final RC2 script in an isolated fixture.

Positive tests

Test Result
PowerShell syntax PASS
Audit on healthy UE 5.8.4 installation HEALTHY / NOT_APPLICABLE
Prepare original UE 5.8.3 fixture FIXTURE_READY
Apply one-field patch ONE_FIELD_PATCH_APPLIED
Independent SHA256 comparison BYTE_IDENTICAL_PATCH_CONFIRMED
Verify patched metadata PATCH_ACCEPTED

The isolated Apply operation generated exactly the same SHA256 as the original successful real-world experiment:

86704755844536D28731F553CA93ADD779725D2E516E61D08CC2527427D693E4

This establishes that the tested implementation reproduced the same byte-level .item modification.

Negative tests

I also tested three unsafe scenarios.

N1 — Active EOSH pending

APPLY_REFUSED

Result: PASS

The script refused to apply the patch.

The relevant .item and .egi files remained unchanged.

N2 — Revision mismatch

APPLY_REFUSED

Result: PASS

The script detected inconsistent revisions and refused the patch.

The relevant files remained unchanged.

N3 — EOSH changed after Apply

VERIFY_FAILED - DO NOT UPDATE

Result: PASS

After a successful isolated Apply, I deliberately modified the test EOSH revision.

Verify correctly rejected the changed installation state.

Overall test results

FINAL RC2 POSITIVE TESTS: PASS

N1 Active pending:    PASS
N2 Revision mismatch: PASS
N3 EOSH changed:      PASS

ALL NEGATIVE TESTS PASSED

Testing limitation: The isolated end-to-end test used authentic EGL/EOSH metadata, but the original physical UE 5.8.3 manifest SHA256 was simulated from its previously recorded value because that manifest was not included in the snapshot.

The real UE 5.8.3 → 5.8.4 update was completed earlier using the same one-field patch mechanism, not by running this exact final public script against the live installation.

These are separate validation results and should not be confused.


10. Manual examination for advanced users

For experienced users who understand EGL/EOSH metadata and its associated risks, the one-field change can also be investigated manually if the script refuses to proceed.

However, this should only be considered when the installation matches the specific conditions documented above.

The relevant live EGL metadata file is located at:

C:\ProgramData\Epic\EpicGamesLauncher\Data\Manifests\<InstallationID>.item

In my confirmed case, the relevant value was:

Before:

"ManifestHash": "7824ea53198b0f36a0a291bb3ee11f563912056d"

After:

"ManifestHash": ""

Important: Do not clear arbitrary non-empty ManifestHash values.

A different value may be legitimate or may indicate a different installation state.

Before considering a manual experiment:

  • Completely close Epic Games Launcher and EpicWebHelper.
  • Confirm that the installed version and EOSH version agree.
  • Confirm that .item and .egi revisions agree.
  • Ensure there is no active EOSH pending transaction.
  • Ensure no pending .item, pending installed manifest, or BPS operation remains.
  • Back up the original .item and relevant metadata.
  • Preserve the original file encoding and all unrelated properties.

Do not manually modify:

EOSH .egi
Revision.json
EoshRevision
LauncherInstalled.dat
Plugin registrations

If the installation does not match the documented fingerprint, the safest approach is to preserve the logs and metadata for Epic rather than force the workaround.

Also, do not restore old metadata after EGL has already started a new update transaction.


11. Additional observation: LauncherInstalled.dat

One interesting detail remained after the successful update.

The live .item, EOSH record, installed manifest, and physical engine build all indicated UE 5.8.4.

EGL displayed:

Launch

However, LauncherInstalled.dat still reported:

5.8.3-58210709+++UE5+Release-5.8-Windows

This discrepancy did not prevent the installation from working.

I intentionally left the file unchanged.

It may be useful for Epic to investigate which metadata source is authoritative during installation preparation, commit, and finalization.


12. Final update from my side

With Epic moving toward the new Beta Launcher, I intend this to be my final update to this thread for now.

Over the course of the investigation, the issue has been narrowed down considerably.

What initially appeared to be an endless Resume loop was traced through patch activity, EOSH installation-state transitions, manifest fingerprints, and revision changes.

Eventually, a specific stale ManifestHash value was identified, and removing that value alone allowed the update to complete successfully.

I hope these findings provide the Epic team with a useful starting point to reproduce the behavior, inspect the relevant launcher state-management logic, and implement an appropriate permanent fix.

The exact internal root cause still needs to be confirmed by Epic.


13. A personal closing note

I also want to clarify something about why I spent so much time investigating this.

It was never about proving that I know better than Epic’s engineers or anyone else here.

I’m a bit of a perfectionist by nature, and when something doesn’t work as expected, my curiosity rarely lets me leave it unexplained. I enjoy following the evidence, testing different possibilities, and trying to understand what is really happening beneath the surface.

I suppose you could say that once a problem catches my attention, it has a hard time escaping without revealing at least a few of its secrets. :slight_smile:

What started as a frustrating launcher issue gradually became a genuinely interesting technical investigation.

Beyond satisfying my own curiosity, I wanted to contribute something useful toward improving Unreal Engine and its surrounding tools.

I believe many developers here share that same passion. We build with this engine, encounter challenges, investigate them, and sometimes discover something worth sharing with the community.

If these findings help Epic identify the underlying issue, or save another developer from going through the same troubleshooting process, then every hour spent investigating was worthwhile.

Thanks to everyone who followed this investigation, and to the Epic team for taking a look.

Happy developing!