Skip to content

NSIS uninstaller $INSTDIR resolves to Program Files (x86) on 64-bit after upgrade #9658

Description

@JamieRuderman

Bug Description

After upgrading a 64-bit NSIS app (installed in C:\Program Files\App), the uninstaller's $INSTDIR resolves to C:\Program Files (x86)\App instead of the correct 64-bit path. This causes the uninstall to silently fail — the app directory is not removed.

Fresh install → uninstall works correctly. Only the upgrade → uninstall path is broken.

Steps to Reproduce

  1. Install a 64-bit electron-builder NSIS app (installs to C:\Program Files\App)
  2. Upgrade to a newer version (upgrade succeeds, correct path)
  3. Uninstall the app
  4. App directory remains at C:\Program Files\App — uninstaller targeted C:\Program Files (x86)\App

Evidence

Uninstall log showing $INSTDIR wrong after upgrade:

# During UPDATE — old uninstaller runs with correct path:
Start CustomRemoveFiles 3.41.0
Command: "C:\Program Files\Remote.It\resources\remoteit" agent uninstall
Result Code: 0
RMDir C:\Program Files\Remote.It

# Later UNINSTALL — $INSTDIR is wrong:
Start CustomRemoveFiles 3.45.2
Command: "C:\Program Files (x86)\Remote.It\resources\remoteit" agent uninstall
Result Code: error
RMDir C:\Program Files (x86)\Remote.It    ← wrong path, app left behind

The registry has the correct value in the 64-bit view:

HKEY_LOCAL_MACHINE\SOFTWARE\{app-guid}
    InstallLocation    REG_SZ    C:\Program Files\Remote.It

No entry exists under WOW6432Node (32-bit view).

Analysis

un.onInit in uninstaller.nsh calls check64BitAndSetRegViewinitMultiUsersetInstallModePerAllUsers, which should read InstallLocation from the 64-bit registry and set $INSTDIR correctly. Despite the registry containing the correct value under the 64-bit view, $INSTDIR defaults to $PROGRAMFILES (the 32-bit path) in the upgrade→uninstall flow.

Notably, during BUILD_UNINSTALLER in installer.nsi, the .onInit function skips check64BitAndSetRegView entirely:

Function .onInit
  !ifmacrodef preInit
    !insertmacro preInit
  !endif

  !ifdef BUILD_UNINSTALLER
    WriteUninstaller "${UNINSTALLER_OUT_FILE}"
    !insertmacro quitSuccess          ; ← exits here
  !else
    !insertmacro check64BitAndSetRegView  ; ← never reached for uninstaller build
    !insertmacro initMultiUser
  !endif
FunctionEnd

This may contribute to the uninstaller binary's default $INSTDIR being set to the 32-bit path.

Workaround

We worked around this by explicitly reading the registry at the start of our customRemoveFiles macro:

SetRegView 64
ReadRegStr $0 HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation
${ifNot} $0 == ""
    StrCpy $INSTDIR $0
${endIf}

Log confirming the workaround corrects the path:

INSTDIR before fix: C:\Program Files (x86)\Remote.It
INSTDIR after fix: C:\Program Files\Remote.It

Environment

  • electron-builder: 26.8.1
  • OS: Windows 11 x64
  • NSIS config: oneClick: false, perMachine: true, allowToChangeInstallationDirectory: true
  • Architecture: x64 app (APP_64 defined)

Expected Behavior

$INSTDIR in the uninstaller should resolve to the actual install location (C:\Program Files\App) regardless of whether the app was freshly installed or upgraded.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions