TypeScript

Fix npm ERR! Unexpected token '.' with nvm-windows

How to confirm the broken libnpmfund file in under a minute, why only npm 8.3.1 and later trip on it, and the reinstall that actually repairs the Node version you already have.

Mahdi Ben RhoumaMahdi Ben Rhouma
7 min read

TL;DR#

npm ERR! Unexpected token '.' on Windows, with Node installed through nvm-windows, means npm's own files are broken, not your project. The file node_modules\npm\node_modules\libnpmfund inside that Node version holds one line of text, ../workspaces/libnpmfund, where npm expects a folder. Node loads it as JavaScript and fails on the first dot.

The fix: update nvm-windows, open an elevated terminal, then nvm uninstall and nvm install the affected Node version so npm is laid down again as a real folder. Updating nvm alone does not repair a version that is already installed.

The question comes from Stack Overflow: Node 17.4.0 and npm 8.3.1 installed with nvm-windows, and every npm install fails the same way, whatever the package:

text
PS C:\myRepo> npm install -g npm
npm ERR! Unexpected token '.'

The debug log points at the culprit. A full log posted in npm/cli issue 4234 for the same setup shows it:

text
28 verbose stack C:\Users\halcw\AppData\Roaming\nvm\v17.4.0\node_modules\npm\node_modules\libnpmfund:1
28 verbose stack ../workspaces/libnpmfund
28 verbose stack ^
28 verbose stack
28 verbose stack SyntaxError: Unexpected token '.'

Line 1 of a "module" called libnpmfund is the text ../workspaces/libnpmfund. That is a symbolic link target written out as file content.

Three facts, each in public source code, explain the error.

npm 8.3.1 turned its internal libraries into links. In the npm repository, the v8.3.1 tag stores eleven entries under node_modules as symbolic links (Git mode 120000): libnpmaccess, libnpmdiff, libnpmexec, libnpmfund, libnpmhook, libnpmorg, libnpmpack, libnpmpublish, libnpmsearch, libnpmteam and libnpmversion. Each points into the workspaces folder, for example libnpmfund to ../workspaces/libnpmfund. In the v8.3.0 tag, only libnpmdiff is a link. That is why the error appeared with npm 8.3.1, and why the opening report of issue 4234 says npm "was fine on v8.3.0".

Every install loads libnpmfund. In npm 8.3.1, lib/utils/reify-output.js requires it at line 16 to print the funding summary, and the stack in issue 4234 ends at reify-output.js:16:38. The command fails while npm loads its own code, before it reads package.json or contacts the registry. That is why the package name makes no difference, and why npm install -g npm, the usual "upgrade npm" escape route, fails too.

nvm-windows 1.1.7 could not extract links. Old nvm-windows releases downloaded node.exe on its own, then fetched npm separately as the GitHub source archive of the npm repository (web.go in 1.1.7 builds that URL from the npm/cli archive path plus v<version>.zip). Its Unzip function creates every entry that is not a directory with os.OpenFile and copies the bytes in. A link entry in a zip file carries its target as its content, so each of the eleven links became a small text file. Issue 4234 was retitled to "npm ERR! Unexpected token '.' with nvm-windows <= 1.1.7" once this was clear.

nvm-windows 1.1.8 changed the download: for Node 16.9.0 and later, web.go in 1.1.8 fetches the official node-v<version>-win-x64.zip from nodejs.org, which already contains npm, and skips the separate npm archive. In Node's own source for v17.4.0, deps/npm/node_modules/libnpmfund is an ordinary folder. Note that the 1.1.9 release notes do not mention this bug; the Stack Overflow answer that recommends 1.1.9 works because 1.1.9 includes the 1.1.8 change. Back in issue 4234, one participant who tried Node's own Windows installers reports: "I wasn't able to reproduce this error using the official installers."

Reproducing the broken extraction#

The mechanism can be checked without Windows. On 24 October 2026, the Unzip function of nvm-windows 1.1.7 was compiled verbatim from its source with Go and used to extract the npm v8.3.1 and v8.3.0 source archives from GitHub, the same downloads 1.1.7 makes. The extracted npm was then run with Node 17.4.0 in the official node:17.4.0-alpine image. This is Linux, so it proves what the extraction produces and how npm reacts to it, not the Windows permission behaviour discussed below.

What the extraction left where the link should be, and what npm does with it:

text
### npm v8.3.1 GitHub archive, extracted with nvm-windows 1.1.7's Unzip()
regular file
../workspaces/libnpmfund
 
$ npm install -g npm   (broken npm)
npm ERR! Unexpected token '.'

Any package name gives the same result: installing the small is-number package into a fresh project fails identically. The debug log ends exactly where the stacks posted in issue 4234 end:

text
28 verbose stack SyntaxError: Unexpected token '.'
28 verbose stack     at Object.compileFunction (node:vm:352:18)
28 verbose stack     at require (node:internal/modules/cjs/helpers:102:18)
28 verbose stack     at Object.<anonymous> (/work/nvm-npm-8.3.1/cli-8.3.1/lib/utils/reify-output.js:16:38)

Meanwhile the same broken copy answers a version query without complaint:

text
$ npm -v   (broken npm)
8.3.1
exit=0

Three controls, each changing one thing:

  • npm 8.3.0, same extraction function: libnpmfund comes out as a directory and npm install is-number succeeds. Only libnpmdiff, the single link in that tag, comes out as a plain file.
  • npm 8.3.1, same archive, extracted with Alpine's unzip: libnpmfund is a symbolic link to ../workspaces/libnpmfund, and the install succeeds.
  • The npm bundled with the official Node 17.4.0 image: libnpmfund is a directory, and the install succeeds.
text
### fix: same v8.3.1 archive, extracted with a symlink-aware unzip
symbolic link
../workspaces/libnpmfund
8.3.1
 
added 1 package in 4s
exit=0

So the error needs both halves: an npm version that ships links, and an extractor that writes links as files. Neither alone produces it.

The error did not stop entirely with newer nvm-windows. nvm-windows issue 814 shows the same one-line file on 1.1.7, and issue 871 reports it on 1.1.9 and 1.1.10 with Node 18. The nvm-windows maintainer explains in issue 871 that "Sometimes npm creates text files instead of symbolic links to directories, causing this error", and in issue 814 that Windows needs administrative rights, or comparable permissions, to create symlinks. In both threads, reinstalling the Node version is what cleared it.

Fix: reinstall the broken Node version with a current nvm-windows#

  1. Check which nvm-windows you have. Anything at 1.1.7 or below downloads npm through the archive path above.

    powershell
    nvm version
  2. Update nvm-windows from its releases page (the installer, or nvm-update.zip for an in-place upgrade). If you installed nvm-windows with Chocolatey, a commenter in issue 4234 had to request the newer version explicitly while the community package caught up, so run nvm version again afterwards.

  3. Open PowerShell as administrator. nvm use recreates the nodejs symlink that points at the active version, and the nvm-windows maintainer states in issue 814 that Windows requires administrative privileges (or comparable permissions) to create symlinks. In the same thread, a user who fixed it ran the uninstall and install from an administrator console.

  4. Remove the broken version and install it again. Use the version from your nvm list; the asker's was 17.4.0.

    powershell
    nvm uninstall 17.4.0
    nvm install 17.4.0
    nvm use 17.4.0
  5. Repeat step 4 for every other Node version that shows the error. Each version folder has its own copy of npm, and only the ones extracted the broken way are affected.

If nvm uninstall or nvm use now stops with exit status 1: Access is denied, the terminal is not elevated: that is a separate symlink permission problem, covered step by step in nvm use "exit status 1: Access is denied" on Windows, including the Developer Mode option.

Verify the fix#

Look at the file itself instead of trusting a reinstall message. In the asker's log, nvm keeps its versions under %APPDATA%\nvm:

powershell
$lib = "$env:APPDATA\nvm\v17.4.0\node_modules\npm\node_modules\libnpmfund"
Test-Path $lib -PathType Leaf
Get-Item $lib | Select-Object Mode, LinkType, Target

Test-Path … -PathType Leaf returns True when libnpmfund is a plain file, which is the broken state. After the reinstall it must return False, and Get-Item shows a directory. Then run any install in a project:

powershell
npm -v
npm install

npm -v alone is not a test: printing the version does not load libnpmfund, which is why npm -v reported 8.3.1 in the question while every install failed.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

Workarounds people use, and what each one costs#

Switching to an older Node (the third Stack Overflow answer) works when that version's npm predates 8.3.1: its libnpmfund was extracted as an ordinary folder. It is not a clean install, though. In the reproduction above, the 8.3.0 extraction still left libnpmdiff as a plain file; npm install simply never loads it. The newer version stays broken, and you lose whatever you needed the newer Node for.

Repairing the links by hand is possible, since the target is written in each file, but eleven packages are affected in npm 8.3.1 alone. A reinstall from an elevated shell is shorter and repeatable.

CI runners. Issue 4234 also has a report from GitHub Actions Windows images running Node 17.4.0 with npm 8.3.1. The thread does not establish how Node was installed on those runners, so check that first: if the job installs it through an old nvm-windows, the fix above applies; otherwise the cause is not the one described here.

Not the same error#

Several other errors print "Unexpected token" while npm or a CLI starts. If the log points at a ?? operator inside a package such as typescript/lib/tsc.js, the Node runtime is too old for the code, which is the case in tsc SyntaxError: Unexpected token '?' on old Node.js. The nvm-windows case is recognisable by its stack: the file at fault sits inside node_modules\npm\node_modules, its line 1 is a relative path, and the file name has no .js extension. A third family, where node_modules was installed for another platform and a native binary is missing, is explained in Cannot find module @rollup/rollup-win32-x64-msvc; it also clears with a clean reinstall, but on the project side rather than inside Node's own npm.

Once the reinstalled Node passes the Test-Path check and npm install finishes in a project, the repair is complete. The cause was never your project, so nothing in package.json or the lockfile needs to change.

Further reading: Fix ERR spawn EINVAL from npx install-peerdeps on Windows. Also see Fix pnpm ERR_PNPM_LINKING_FAILED on Windows.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote