#701

[Bug] Windows installer 2.0.290 fails with error 1603 during ValidateInstallRootPreview

OpenVirtualGIT20opened 6d ago

Bug Symptoms

Bug description

I'm experiencing an installation failure with Vibepollo 2.0.290 on Windows.

When attempting to reinstall Vibepollo, the installer successfully removes the existing installation but then fails with MSI error 1603.

The installation is blocked during the "ValidateInstallRootPreview" custom action.

Steps to reproduce

  1. Start with Vibepollo installed in "C:\Program Files\Apollo".
  2. Run the Windows installer to reinstall/update Vibepollo.
  3. The existing installation is removed successfully (exit code 0).
  4. The new installation fails during directory validation.

Actual behavior

The installer returns:

The install folder or an existing product directory is unsafe, writable by an untrusted account, or contains a reparse point. Close the host and run the bootstrapper from an elevated account.

CustomAction ValidateInstallRootPreview returned actual error code 1603 Action ended: ValidateInstallRootPreview. Return value 3.

However, the MSI log confirms:

MsiRunningElevated = 1 Privileged = 1 AdminUser = 1

Additional information

  • Installer version: 2.0.290
  • Platform: Windows x64
  • Installation directory: "C:\Program Files\Apollo"
  • Failure date: November 1, 2026
  • MSI error code: 1603
  • The previous version was successfully removed (exit code 0).
  • Previous installations of version 2.0.290 succeeded on October 25 and October 26.
  • The latest MSI log also reports "MsiSystemRebootPending = 1".

Could you help identify what causes "ValidateInstallRootPreview" to reject the installation directory even when the installer is running with elevated privileges?

Is there a safe way to determine the specific directory or permission that is triggering this validation?

I can provide the full installation logs if additional information is needed.

Expected Behavior

The installer should complete successfully, or provide a specific explanation identifying which directory, permission, or reparse point is causing the security validation to fail.

Ideally, the existing installation should not be removed before this validation succeeds.

Windows Version

25H2

Package

Windows - exe installer

GPU Type

NVIDIA

GPU Model

5070

GPU Driver Version

latest

Capture Method

None

Apps

undefined

Logs (Optional but Recommended)

vibepollo-issue-logs-redacted-20261101.txt

Screenshot (Optional)

undefined

Activity

11
markmghali6d ago

same issue

jcbrizzy6d ago

Getting something similar w/ 2.0.3 ..... awesome. Uninstalled everything.. and won't install.

Nonary6d ago

We are comparing this failure across Vibeshine #391, Vibeshine #392, and Vibepollo #701. The current installer log does not identify the rejected path or Windows error. This read-only diagnostic collects the missing details automatically.

Run once and attach one report

  1. Open Windows PowerShell as administrator from the Start menu.
  2. Copy and paste this entire command, then press Enter. It downloads the diagnostic embedded in this comment, verifies its SHA-256 checksum, and runs it. There is no need to save a script manually or change your system's execution-policy setting.
& { $ErrorActionPreference='Stop'; try { $c=Invoke-RestMethod -Uri 'https://api.github.com/repos/Nonary/Vibepollo/issues/comments/6561597946' -Headers @{'User-Agent'='InstallerFolderDiagnostic'}; $m=[regex]::Match($c.body,'(?s)<!-- installer-diagnostic-v2 -->\s*```powershell\r?\n(.*?)\r?\n```'); if(-not $m.Success){throw 'Diagnostic script was not found in the issue comment.'}; $s=$m.Groups[1].Value.Replace("`r",'').Trim(); $h=[Security.Cryptography.SHA256]::Create(); $hash=[BitConverter]::ToString($h.ComputeHash([Text.Encoding]::UTF8.GetBytes($s))).Replace('-','').ToLowerInvariant(); $h.Dispose(); if($hash -ne 'f5219668a649988a598d600b8a0c4d3b7646a9e4e5fdb5da759122699c86d4b2'){throw 'Diagnostic script checksum mismatch. Please report this instead of running it.'}; $p=Join-Path $env:TEMP ('installer-folder-diagnostic-'+[guid]::NewGuid().ToString('N')+'.ps1'); [IO.File]::WriteAllText($p,$s,(New-Object Text.UTF8Encoding($false))); & "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -ExecutionPolicy Bypass -File $p } catch { Write-Host $_ -ForegroundColor Red } }
  1. When it finishes, File Explorer opens with the report selected. Drag that text file into a reply here. If Explorer cannot open, the report's full path is printed in PowerShell. If the command fails, paste the displayed error instead.

The collector automatically checks the normal installation locations plus locations found in relevant installer registrations. It records ancestor and installation-file ownership/permissions, raw security descriptors, reparse points, native file-open/security-query errors, MSI product/directory identities, Windows build, elevation, and reboot markers. Missing installation folders are recorded too. No separate screenshots, registry exports, or commands are needed for the initial collection.

It does not change permissions, uninstall anything, stop/start services, execute installed application code, or read configuration/credential file contents. It writes the diagnostic script, its text report, and temporary compiler files; it opens File Explorer at the end. It may take a few minutes for a large installation. The report contains paths/account SIDs, so review or redact identifying details before uploading it. The report is never uploaded automatically.

Validation so far: PowerShell syntax, embedded C# compilation, and mocked permission-classification checks passed. The native Windows probes still need an affected Windows machine; the collector records probe failures in the report. This gathers the evidence needed to distinguish an unsafe directory from a guard compatibility problem; it does not assume either outcome or guarantee a fix from one report.

Diagnostic source (automatically downloaded by the command above)
# Windows PowerShell 5.1+. Read-only except for the report and compiler temporary files.
# Does not start/stop services, change ACLs, or read file contents.
[CmdletBinding()]
param(
    [string[]]$InstallRoot = @(),
    [ValidateRange(1,100000)][int]$MaxEntries = 20000
)
$ErrorActionPreference = 'Stop'
$report = Join-Path $env:TEMP ('installer-folder-diagnostic-{0}.txt' -f (Get-Date -Format 'yyyyMMdd-HHmmss'))
$lines = New-Object 'System.Collections.Generic.List[string]'
function Log([string]$Text) { $lines.Add($Text) }
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
Log 'Vibeshine / Vibepollo installer folder diagnostic v2'
Log ('Time UTC: ' + [DateTime]::UtcNow.ToString('o'))
Log ('Elevated: ' + $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
Log ('PowerShell: ' + $PSVersionTable.PSVersion.ToString())
Log ('OS: ' + [Environment]::OSVersion.VersionString)
Log ('64-bit PowerShell: ' + [Environment]::Is64BitProcess)
Log ('Process user SID: ' + $identity.User.Value)
Log ('ProgramFiles environment: ' + $env:ProgramFiles)
Log ('ProgramW6432 environment: ' + $env:ProgramW6432)
Log ('ProgramFiles(x86) environment: ' + ${env:ProgramFiles(x86)})
Log 'Read-only inspection; no file contents collected. Paths and account SIDs may identify users.'
Log 'The preview-open probe closes each handle immediately; this is not a full reproduction of the MSI guard.'

# Match the native guard's preview access/share flags, without following a
# final-component reparse point and without creating or modifying any object.
try {
    if (-not ('InstallerFolderDiagnostic.Native' -as [type])) {
        Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
namespace InstallerFolderDiagnostic {
    public class ProbeResult {
        public int OpenError;
        public uint SecurityError;
        public int DescriptorError;
        public string Sddl;
    }
    public static class Native {
        [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        private static extern IntPtr CreateFileW(string path, uint access,
            uint share, IntPtr security, uint disposition, uint flags, IntPtr template);
        [DllImport("kernel32.dll", SetLastError=true)]
        private static extern bool CloseHandle(IntPtr handle);
        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern uint GetSecurityInfo(IntPtr handle, int objectType,
            uint information, out IntPtr owner, out IntPtr group, out IntPtr dacl,
            out IntPtr sacl, out IntPtr descriptor);
        [DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        private static extern bool ConvertSecurityDescriptorToStringSecurityDescriptorW(
            IntPtr descriptor, uint revision, uint information, out IntPtr text, out uint length);
        [DllImport("kernel32.dll")]
        private static extern IntPtr LocalFree(IntPtr memory);
        [DllImport("msi.dll", CharSet=CharSet.Unicode)]
        private static extern uint MsiEnumRelatedProductsW(string upgrade, uint reserved, uint index, StringBuilder code);
        [DllImport("msi.dll", CharSet=CharSet.Unicode)]
        private static extern uint MsiGetProductInfoExW(string code, string sid, uint context, string property, StringBuilder value, ref uint length);
        [DllImport("msi.dll", CharSet=CharSet.Unicode)]
        private static extern int MsiGetComponentPathExW(string product, string component, string sid, uint context, StringBuilder value, ref uint length);
        public static string[] RelatedProducts(string upgrade) {
            List<string> codes = new List<string>();
            for (uint i=0; i<4096; i++) {
                StringBuilder code = new StringBuilder(39);
                uint result = MsiEnumRelatedProductsW(upgrade, 0, i, code);
                if (result == 259) return codes.ToArray();
                if (result != 0) throw new System.ComponentModel.Win32Exception((int)result);
                codes.Add(code.ToString());
            }
            throw new Exception("MSI enumeration limit reached");
        }
        public static string ProductInfo(string code, string property) {
            StringBuilder value = new StringBuilder(32768); uint length=32768;
            uint result = MsiGetProductInfoExW(code, null, 4, property, value, ref length);
            if (result != 0) throw new System.ComponentModel.Win32Exception((int)result);
            return value.ToString();
        }
        public static string ComponentPath(string code, string component) {
            StringBuilder value = new StringBuilder(32768); uint length=32768;
            int state = MsiGetComponentPathExW(code, component, null, 4, value, ref length);
            return state == 3 ? value.ToString() : "<MSI component state: " + state + ">";
        }
        public static ProbeResult Preview(string path) {
            ProbeResult result = new ProbeResult();
            IntPtr h = CreateFileW(path, 0x00020100, 3, IntPtr.Zero, 3,
                0x02200000, IntPtr.Zero);
            if (h == new IntPtr(-1)) { result.OpenError=Marshal.GetLastWin32Error(); return result; }
            IntPtr descriptor=IntPtr.Zero, text=IntPtr.Zero;
            try {
                IntPtr owner, group, dacl, sacl;
                result.SecurityError=GetSecurityInfo(h, 1, 5, out owner, out group, out dacl, out sacl, out descriptor);
                if (result.SecurityError == 0) {
                    uint length;
                    if (ConvertSecurityDescriptorToStringSecurityDescriptorW(descriptor,1,5,out text,out length))
                        result.Sddl=Marshal.PtrToStringUni(text);
                    else result.DescriptorError=Marshal.GetLastWin32Error();
                }
                return result;
            } finally {
                if (text != IntPtr.Zero) LocalFree(text);
                if (descriptor != IntPtr.Zero) LocalFree(descriptor);
                CloseHandle(h);
            }
        }
    }
}
'@
    }
    $nativeAvailable = $true
} catch {
    $nativeAvailable = $false
    Log ('Native preview-open probe unavailable: ' + $_.Exception.Message)
}

$trusted = @('S-1-5-18','S-1-5-32-544','S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464')
$roots = New-Object 'System.Collections.Generic.List[string]'
function Add-Root([string]$Path) {
    if ([string]::IsNullOrWhiteSpace($Path)) { return }
    if ($Path -notmatch '^[a-zA-Z]:\\') { Log ('Non-local/invalid registered path (not inspected): ' + $Path); return }
    try {
        $full = [IO.Path]::GetFullPath($Path).TrimEnd('\')
        if ($full.Length -le 3) { Log ('Drive root registration (not recursively inspected): ' + $full); return }
        if (-not $roots.Contains($full)) { $roots.Add($full) }
    } catch { Log ('Invalid registered path: ' + $Path + '; ' + $_.Exception.Message) }
}
foreach ($root in $InstallRoot) { Add-Root $root }
foreach ($base in @($env:ProgramW6432,$env:ProgramFiles,${env:ProgramFiles(x86)})) {
    if ($base) { foreach ($name in @('Sunshine','Apollo','Vibeshine','Vibepollo')) { Add-Root (Join-Path $base $name) } }
}
Log ''
Log 'Relevant uninstall registrations (read-only; no uninstall commands executed):'
foreach ($hive in @([Microsoft.Win32.RegistryHive]::LocalMachine,[Microsoft.Win32.RegistryHive]::CurrentUser)) {
    foreach ($view in @([Microsoft.Win32.RegistryView]::Registry64,[Microsoft.Win32.RegistryView]::Registry32)) {
        $baseKey = $null; $uninstall = $null
        try {
            $baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey($hive,$view)
            $uninstall = $baseKey.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',$false)
            if ($null -eq $uninstall) { continue }
            foreach ($keyName in $uninstall.GetSubKeyNames()) {
                $key = $null
                try {
                    $key = $uninstall.OpenSubKey($keyName,$false)
                    if ($null -eq $key) { continue }
                    $displayName = [string]$key.GetValue('DisplayName')
                    if ($displayName -notmatch '(?i)sunshine|vibeshine|apollo|vibepollo' -and $keyName -notmatch '^(Sunshine|Vibeshine|Apollo|Vibepollo)$') { continue }
                    Log ('REGISTRY: ' + $hive + '/' + $view + '/' + $keyName)
                    foreach ($field in @('DisplayName','DisplayVersion','WindowsInstaller','ProductCode','InstallLocation')) {
                        Log ($field + ': ' + [string]$key.GetValue($field))
                        if ($null -ne $key.GetValue($field)) { Log ($field + ' registry type: ' + $key.GetValueKind($field)) }
                    }
                    Add-Root ([string]$key.GetValue('InstallLocation'))
                } catch { Log ('Registration read error: ' + $_.Exception.Message) }
                finally { if ($key) { $key.Dispose() } }
            }
        } catch { Log ('Registry read error: ' + $_.Exception.Message) }
        finally { if ($uninstall) { $uninstall.Dispose() }; if ($baseKey) { $baseKey.Dispose() } }
    }
}
if ($nativeAvailable) {
    foreach ($upgrade in @('{C2C36624-2D9C-4AFD-9C79-6B7861AE4A0D}','{E3FA501A-85F8-4187-85A7-D6E6BDC7EDA1}')) {
        try {
            $products = @([InstallerFolderDiagnostic.Native]::RelatedProducts($upgrade))
            Log ('MSI upgrade family: ' + $upgrade + '; related products: ' + $products.Count)
            foreach ($product in $products) {
                Log ('MSI product: ' + $product)
                foreach ($field in @('ProductName','VersionString','InstallLocation','LocalPackage')) {
                    try {
                        $value = [InstallerFolderDiagnostic.Native]::ProductInfo($product,$field)
                        Log ($field + ': ' + $value)
                        if ($field -eq 'InstallLocation') { Add-Root $value }
                    } catch { Log ($field + ' query error: ' + $_.Exception.Message) }
                }
                foreach ($component in @('{B6D8A6A3-63B7-4C3F-8A2C-2C8F2B2F3B61}','{640D87CF-69A4-4F54-AE29-941F78D020B2}')) {
                    try {
                        $value = [InstallerFolderDiagnostic.Native]::ComponentPath($product,$component)
                        Log ('Directory component ' + $component + ': ' + $value)
                        if ($value -notmatch '^<') { Add-Root $value }
                    } catch { Log ('Directory component query error: ' + $_.Exception.Message) }
                }
            }
        } catch { Log ('Related MSI product query error: ' + $_.Exception.Message) }
    }
}
$windows = Get-ItemProperty -LiteralPath 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction SilentlyContinue
if ($windows) { Log ('Windows build: {0}.{1}; display version: {2}' -f $windows.CurrentBuildNumber,$windows.UBR,$windows.DisplayVersion) }
foreach ($pendingKey in @('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending','HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired')) {
    Log ('Reboot marker ' + $pendingKey + ': ' + (Test-Path -LiteralPath $pendingKey))
}
$seen = @{}
$script:count = 0
$script:flagged = 0
function Inspect-Path([string]$Path, [bool]$Strict, [bool]$AlwaysPrint) {
    if ($seen.ContainsKey($Path)) { return $seen[$Path] }
    $seen[$Path] = $null
    $script:count++
    $details = New-Object 'System.Collections.Generic.List[string]'
    $reasons = New-Object 'System.Collections.Generic.List[string]'
    $item = $null
    try {
        $item = Get-Item -LiteralPath $Path -Force -ErrorAction Stop
        $details.Add('Attributes: ' + $item.Attributes)
        if ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) {
            $reasons.Add('Reparse point; descendants will not be inspected')
        }
        if ($nativeAvailable) {
            $probe = [InstallerFolderDiagnostic.Native]::Preview($Path)
            $details.Add('Native preview-open Win32 error: ' + $probe.OpenError)
            $details.Add('Native GetSecurityInfo error: ' + $probe.SecurityError)
            $details.Add('Native SDDL conversion error: ' + $probe.DescriptorError)
            $details.Add('Native owner/DACL SDDL: ' + $probe.Sddl)
            if ($probe.OpenError -ne 0) { $reasons.Add('Native preview-open failed: ' + $probe.OpenError) }
            if ($probe.SecurityError -ne 0) { $reasons.Add('Native security query failed: ' + $probe.SecurityError) }
            if ($probe.DescriptorError -ne 0) { $reasons.Add('Native SDDL conversion failed: ' + $probe.DescriptorError) }
        }
        $acl = Get-Acl -LiteralPath $Path -ErrorAction Stop
        $details.Add('SDDL: ' + $acl.Sddl)
        $owner = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
        $details.Add('Owner SID: ' + $owner)
        $details.Add('DACL protected: ' + $acl.AreAccessRulesProtected)
        if ($trusted -notcontains $owner) { $reasons.Add('Owner is outside native guard whitelist') }
        $rules = $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])
        foreach ($rule in $rules) {
            $sid = $rule.IdentityReference.Value
            $mask = ([long]$rule.FileSystemRights) -band 4294967295L
            $inheritOnly = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -ne 0
            $details.Add(('ACE: SID={0}; type={1}; mask=0x{2:X8}; inherited={3}; inheritance={4}; propagation={5}' -f $sid,$rule.AccessControlType,$mask,$rule.IsInherited,$rule.InheritanceFlags,$rule.PropagationFlags))
            if ($rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) { continue }
            if (($inheritOnly -and -not $Strict) -or ($trusted -contains $sid) -or ($inheritOnly -and $sid -eq 'S-1-3-0')) { continue }
            $unsafeMask = 0x500D0040L
            if ($Strict) { $unsafeMask = $unsafeMask -bor 0x116L }
            if (($mask -band $unsafeMask) -ne 0) { $reasons.Add('Allow ACE rejected by native guard mask: ' + $sid) }
        }
    } catch {
        $reasons.Add('Inspection error: ' + $_.Exception.GetType().FullName + '; HResult=' + $_.Exception.HResult + '; ' + $_.Exception.Message)
    }
    if ($AlwaysPrint -or $reasons.Count -gt 0) {
        Log ''
        Log ('PATH: ' + $Path)
        Log ('Strict mutation check: ' + $Strict)
        foreach ($reason in $reasons) { Log ('CHECK: ' + $reason) }
        foreach ($detail in $details) { Log $detail }
    }
    if ($reasons.Count -gt 0) { $script:flagged++ }
    $seen[$Path] = $item
    return $item
}

try {
    foreach ($root in $roots) {
        $root = [IO.Path]::GetFullPath($root).TrimEnd('\')
        Log ('Requested install root: ' + $root)
        $ancestors = New-Object 'System.Collections.Generic.List[string]'
        $path = $root
        while ($path) {
            $ancestors.Insert(0,$path)
            $parent = [IO.Directory]::GetParent($path)
            if ($null -eq $parent) { break }
            $path = $parent.FullName
        }
        $rootItem = $null
        $redirected = $false
        foreach ($path in $ancestors) {
            $item = Inspect-Path $path ($path.Length -gt 3) $true
            if ($null -ne $item -and ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) { $redirected = $true; break }
            if ($path -eq $root) { $rootItem = $item }
        }
        if ($redirected -or $null -eq $rootItem -or -not $rootItem.PSIsContainer) { continue }
        $safeToRecurse = $false
        foreach ($base in @($env:ProgramW6432,$env:ProgramFiles,${env:ProgramFiles(x86)})) {
            if ($base -and $root.StartsWith($base.TrimEnd('\') + '\',[StringComparison]::OrdinalIgnoreCase)) { $safeToRecurse = $true }
        }
        foreach ($explicitRoot in $InstallRoot) { if ($root -eq $explicitRoot.TrimEnd('\')) { $safeToRecurse = $true } }
        if (-not $safeToRecurse) { Log ('Only root/ancestors inspected outside Program Files: ' + $root); continue }
        $pending = New-Object 'System.Collections.Generic.Stack[string]'
        $pending.Push($root)
        while ($pending.Count -gt 0 -and $script:count -lt $MaxEntries) {
            Write-Progress -Activity 'Collecting installer diagnostics' -Status ('Inspected ' + $script:count + ' entries')
            $directory = $pending.Pop()
            try {
                foreach ($child in (Get-ChildItem -LiteralPath $directory -Force -ErrorAction Stop)) {
                    if ($script:count -ge $MaxEntries) { break }
                    $item = Inspect-Path $child.FullName $true $false
                    if ($null -ne $item -and $item.PSIsContainer -and -not ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) { $pending.Push($item.FullName) }
                }
            } catch { Log ('Enumeration error at ' + $directory + ': ' + $_.Exception.Message) }
        }
        if ($script:count -ge $MaxEntries) { Log 'SCAN LIMIT REACHED; descendant inspection is incomplete.' }
    }
} catch { Log ('Diagnostic error: ' + $_.Exception.Message) }
Log ''
Log ('Inspected entries: ' + $script:count + '; entries with checks/errors: ' + $script:flagged)
Log 'No flagged entries does not prove MSI validation will pass: races and concurrent handle pinning are not fully reproduced.'
$lines | Set-Content -LiteralPath $report -Encoding UTF8
Write-Progress -Activity 'Collecting installer diagnostics' -Completed
Write-Host ('Report saved to: ' + $report)
Write-Host 'Review paths and account SIDs before attaching the report to your issue.'
try { Start-Process -FilePath (Join-Path $env:WINDIR 'explorer.exe') -ArgumentList ('/select,"' + $report + '"') } catch { Write-Host 'Could not open File Explorer. Use the report path above.' }
emreerisen6d ago

I ran the read-only installer folder diagnostic from an elevated PowerShell session. The installer still fails with MSI error 1603 during ValidateInstallRootPreview, with the message that the install folder or an existing product directory is unsafe, writable by an untrusted account, or contains a reparse point.

The diagnostic results for this machine:

  • Windows 11, display version 26H2, build 26300.9818
  • Diagnostic ran elevated: True
  • Reboot-pending markers: False
  • For C:\Program Files\Apollo and its parent directories:
    • Native preview-open Win32 error: 0
    • Native GetSecurityInfo error: 0
    • Native SDDL conversion error: 0
    • Apollo directory owner: SYSTEM (S-1-5-18)
    • No suspicious ACL entries or reparse points were reported.
  • The Vibepollo uninstall registration still exists at HKLM\...\Vibepollo and points to C:\Program Files\Apollo\, with version 2.0.2-daily.d20261014.1+66e169c325da.
  • However, the MSI product identity discovered by the diagnostic is not recognized by Windows Installer as currently installed (MsiGetProductInfoEx returns “This action is only valid for products that are currently installed”).

So far, the diagnostic does not show an obvious permissions or reparse-point problem in the Apollo install directory. The stale-looking uninstall/MSI registration may be relevant, but I cannot confirm that it is the cause.

Could you please advise what to try next, or whether you can provide a more detailed/instrumented installer build that identifies exactly which path or validation check is causing ValidateInstallRootPreview to fail?

I have the complete diagnostic report available and can attach/paste it if needed.

blitz2kx5d ago

Same error - same issue. identical to what was posted.

VirtualGIT205d ago

I've tested installer version 2.0.499, and the issue persists.

The new diagnostic message identifies C:\Program Files\Apollo\assets\desktop1.png as the rejected file (reason=owner_or_dacl).

I've checked the file's permissions:

  • Owner: My Windows user account
  • Permissions: My user account has FullControl
  • ACL inheritance: Enabled
  • Reparse point: No, it's a regular file

I've attached a privacy-redacted copy of the latest installation logs (2.0.499).

I can run the additional diagnostic script if these results are insufficient.

vibeshine-install-logs-20261102_111845_REDACTED.txt

emreerisen5d ago

Update from another affected Windows system — installer 2.0.499 (November 2, 2026).

Unlike my previous 2.0.399 attempt, this version completed successfully (MSI exit code 0), but the installer displayed “Install completed with warnings”.

The warning is reproduced in both validation phases:

Could not resolve a registered product folder;
phase=preview category=related role=none
reason=installed_location_unresolved
api=MsiGetComponentPathExW status=4294967295 access=0

Could not resolve a registered product folder;
phase=strict category=related role=none
reason=installed_location_unresolved
api=MsiGetComponentPathExW status=4294967295 access=0

Relevant MSI log details:

  • Product: Vibepollo
  • Product version: 2.0.499.0
  • Product code: {01A1995B-6A4F-75A6-B242-D47CD99925E6}
  • Install root: C:\Program Files\Apollo\
  • Installation ran elevated (MsiRunningElevated = 1).
  • Both ValidateInstallRootPreview and ValidateInstallRoot returned success (Return value 1); the unresolved related-product-folder condition was recorded as a warning.
  • Final MSI result: Installation completed successfully; status 0.

This looks related to the earlier unresolved/stale Windows Installer product registration reported in this issue, but the new version no longer blocks the installation. Could you clarify what registered product/component cannot be resolved here, whether this warning is safe to ignore, and whether any cleanup or repair is needed?

I have the full installer warning report and screenshot from this run. The report also contains prior installer logs from the earlier 2.0.399 failures.

markmghali5d ago

I have also tested the latest installer 2.0.4 and will not install still.

installer-folder-diagnostic-20261102-082053.txt

vibeshine-install-logs-20261101_075608.txt vibeshine-install-logs-20261102_081903.txt

Edit: It fails immediately now. vibepollo as been uninstalled due to the previously failed upgrade as it was midway through it's process.

1337jck5d ago

same issue 2.0.4 did not fix it

danielriosr4d ago

Same error here [v2.0.4]

`Vibepollo install failure report Generated (UTC): 2026-11-03 00:55:09 Destination: GitHub issue or Discord #vibeshine Installer version: 2.0.499 Exit code: 1603 Operation: Install Collected logs: 11

Failure detail: The replacement installer could not validate the install folders. The existing installation has not been removed. ValidateInstallRootPreview failed (Windows Installer 1603). An install path has untrusted ownership or unrestricted permissions; phase=preview category=selected role=drive_ancestor reason=owner_or_dacl api=none status=0 access=0 path=c:\

Next step: Attach this file on GitHub: https://github.com/Nonary/Vibepollo/issues Or Discord (#vibeshine): https://discord.com/invite/CGg5JxN`

markmghali4d ago

v2.0.6 was able to install properly now