Skip to content

Windows build fails with "MSBuild not found" when only VS Build Tools is installed (possiblePaths list has no BuildTools entries) #116

Description

@AlexRMU

Environment

  • OS: Windows 10, x64
  • talib: 2.0.4
  • Node.js: 26
  • Package manager: pnpm
  • Visual Studio: 2022 Build Tools (installed via choco install visualstudio2022-workload-vctools), "Desktop development with C++" workload confirmed present via vswhere

Problem

src/lib/build.js fails during pnpm i / npm install with:

building talib functions...
MSBuild not found. Please install Visual Studio Build Tools.

This happens even though MSBuild is genuinely installed and correctly detected by vswhere.exe:

& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
> C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools

The root cause is that build.js locates MSBuild via a hardcoded list of paths, and that list only covers the Enterprise/Professional/Community editions for 2019/2022 — not BuildTools, which is the edition installed by the standalone Build Tools installer (and by the corresponding Chocolatey/winget packages):

const possiblePaths = [
'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\MSBuild\\Current\\Bin\\MSBuild.exe',
'C:\\Program Files\\Microsoft Visual Studio\\2022\\Professional\\MSBuild\\Current\\Bin\\MSBuild.exe',
'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe',
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Current\\Bin\\MSBuild.exe',
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\MSBuild\\Current\\Bin\\MSBuild.exe',
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe',
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\MSBuild\\15.0\\Bin\\MSBuild.exe',
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\MSBuild\\15.0\\Bin\\MSBuild.exe',
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe',
'C:\\Program Files (x86)\\MSBuild\\14.0\\Bin\\MSBuild.exe',
'C:\\Program Files\\MSBuild\\14.0\\Bin\\MSBuild.exe'
];

Given that Build Tools is the edition Microsoft explicitly recommends for CI/non-interactive installs (and the one most native-module build scripts, including this project's own README, implicitly assume when they tell users to install "Visual Studio Build Tools"), this seems worth fixing directly rather than leaving as a workaround.

What I did as a workaround

Created a directory junction so the existing detection logic finds the BuildTools install under one of the paths it already checks:

mklink /J "C:\Program Files\Microsoft Visual Studio\2022\Community" "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"

This works, but it's a machine-local hack that every developer/CI runner using Build Tools would have to repeat.

Suggested fix

Minimal version — just add the missing BuildTools entries to possiblePaths for each supported year:

'C:\\Program Files\\Microsoft Visual Studio\\2022\\BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe',
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe',
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe',

More robust version — resolve MSBuild dynamically via vswhere.exe (ships with every VS2017+ install, including Build Tools) instead of a hardcoded/editions list, so this doesn't need updating again for future VS releases:

const { execSync } = require('child_process');

function findMSBuildViaVswhere() {
  try {
    const programFilesX86 = process.env['ProgramFiles(x86)'] || process.env['ProgramFiles'];
    const vswherePath = path.join(programFilesX86, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe');
    if (!fs.existsSync(vswherePath)) return null;
    const msbuildPath = execSync(
      `"${vswherePath}" -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\\**\\Bin\\MSBuild.exe`
    ).toString().trim();
    return fs.existsSync(msbuildPath) ? msbuildPath : null;
  } catch (e) {
    return null;
  }
}

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions