Fix tsc SyntaxError: Unexpected token '?' on old Node.js
Find which Node actually runs tsc, move it to a supported runtime or pin a compiler that matches it, and avoid the different error a plain npm install -g typescript now gives on Node 12 and 14.
TL;DR#
SyntaxError: Unexpected token '?' pointing at startIndex ?? 0 inside typescript/lib/tsc.js means your tsc is a TypeScript release that needs a newer Node.js than the one running it. TypeScript 5.1 started shipping ECMAScript 2020 syntax and declares node >=14.17; Node 12 and older cannot parse the ?? operator, so the compiler dies while loading, before it reads your .ts file.
The fix is to run tsc on a current Node LTS, then reinstall TypeScript under that Node. If you cannot leave Node 12 yet, pin typescript@4.9.5. Do not just run npm install -g typescript on the old Node: the current latest is 7.0.2, which needs Node 16.20.0 and fails on Node 12 and 14 with a different error.
The error, reproduced#
The question on Stack Overflow shows a Windows machine using Nodist, running tsc filename.ts. The same failure reproduces on Linux with the official node:12.17.0-alpine Docker image and a global typescript@5.1.6, on 13 October 2026:
/usr/local/lib/node_modules/typescript/lib/tsc.js:93
for (let i = startIndex ?? 0; i < array.length; i++) {
^
SyntaxError: Unexpected token '?'
at wrapSafe (internal/modules/cjs/loader.js:1054:16)
at Module._compile (internal/modules/cjs/loader.js:1102:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)Line 93 is the first ?? in that file; the same expression appears again at line 115. On Node 10.24.1 and Node 12.6.0 the message has no quotes around the question mark, which is the exact form in the Stack Overflow question:
SyntaxError: Unexpected token ?
at Module._compile (internal/modules/cjs/loader.js:723:23)Two details tell you this is a runtime problem and not a problem in your code. The trace points into node_modules/typescript/lib/tsc.js, never into your file. And tsc -v fails the same way: in the reproduction it printed the same SyntaxError instead of a version number, because Node has to parse the whole compiler before it can answer anything.
Why the compiler no longer loads on Node 12#
The TypeScript 5.1 release notes list this under breaking changes:
TypeScript 5.1 now ships JavaScript functionality that was introduced in ECMAScript 2020. As a result, at minimum TypeScript must be run in a reasonably modern runtime. For most users, this means TypeScript now only runs on Node.js 14.17 and later.
The same section shows this exact startIndex ?? 0 frame as the expected failure "under an older version of Node.js such as Node 10 or 12", and links the change in microsoft/TypeScript#53291. The ?? (nullish coalescing) operator is what Node trips on: the Node.js 14.0.0 release notes list "Enables Nullish Coalescing by default" as part of the V8 8.1 update. Any Node before 14.0.0 reads ?? as a stray token.
The floor is also written in each release's engines field on the npm registry. Read with npm view typescript@<version> engines:
| TypeScript | engines.node | Tested here |
|---|---|---|
| 4.9.5 | >=4.2.0 | compiles on Node 12.17.0 |
| 5.0.4 | >=12.20 | outside its range on 12.17.0 |
| 5.1.6, 6.0.3 | >=14.17 | compile on Node 14.21.3; 5.1.6 also on Node 18.20.8 |
7.0.2 (latest) | >=16.20.0 | runs on Node 20.20.2, fails on 12.17.0 and 14.21.3 |
npm does not refuse an install that breaks this range; it only warns. With npm 6.14.4, bundled with Node 12.17.0, the warning reads:
npm WARN notsup Unsupported engine for typescript@5.1.6: wanted: {"node":">=14.17"} (current: {"node":"12.17.0","npm":"6.14.4"})
npm WARN notsup Not compatible with your version of node/npm: typescript@5.1.6The release notes show the newer npm wording, npm WARN EBADENGINE Unsupported engine, from npm 8.19.2. Either way the package is installed, and the error only appears the first time you run tsc.
Fix: run tsc on a supported Node#
-
Check which Node your shell runs. The
tsclauncher starts with#!/usr/bin/env node, so it uses the firstnodeon thePATHof the terminal you type in. Run this in that same terminal:bashnode -vOn Windows,
where nodelists thenodeexecutables found on thePATH, which shows when a version manager such as Nodist and a separate installer both put one there. Ifnode -vprints a version below 14, this is your cause; anything below 14.17 is still outside TypeScript 5.1's supported range, so upgrade either way. If it prints 14 or later, thenoderunningtscis a different copy (see the last section). -
Install and select a current LTS. With nvm on macOS or Linux, the README documents the LTS shortcuts:
bashnvm install --lts nvm use --ltsOn Windows, use the same step in your version manager, or the installer from nodejs.org. The top-voted answer on the question did exactly this with nvm and Node 18.
-
Reinstall TypeScript under the new Node. Run the global install again from the terminal where
node -vnow shows the new version, so the compiler is installed for that Node:bashnpm install -g typescript tsc -vFor a project, prefer a local compiler in
devDependenciesand an npm script; the page on running the project's local tsc instead of a global one shows that setup. Ifnpm install -gthen fails withEACCES, fix the global prefix rather than reaching for sudo.
If you must stay on Node 12 for now#
Pin a compiler whose range includes your runtime. TypeScript 4.9.5 compiled a test file on Node 12.17.0:
npm install -g typescript@4.9.5
tsc -vVersion 4.9.5This is the fix the second answer on the question describes. TypeScript 5.0.4 also compiled the same two-line file on Node 12.17.0, but its declared range is >=12.20, so 12.17 is outside what it supports; do not rely on it. For a project, write the pin into package.json ("typescript": "4.9.5" in devDependencies) so a fresh npm install cannot pull a 5.1+ compiler back in.
Verify the fix#
Compile a small file and run its output. On Node 14.21.3 with TypeScript 5.1.6, the reproduction gave:
Version 5.1.6
+ rm -f hello.js
+ tsc hello.ts
+ echo exit=0
+ node hello.js
exit=0
Hello from Londontsc -v printing a version is the real signal: under the broken pairing it never gets that far. Then run your usual build, such as npx tsc -p . or your build script, from the same terminal.
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.
Plain npm install -g typescript on Node 12 or 14 now fails differently#
Many readers follow "install the latest TypeScript" on the old Node. Since TypeScript 7.0.2 became latest, that no longer produces the ?? error. On Node 12.17.0 and on Node 14.21.3, the install succeeds with warnings, then tsc -v fails like this (Node 14.21.3):
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension "" for /usr/local/lib/node_modules/typescript/bin/tsc
at new NodeError (internal/errors.js:322:7)
at Loader.defaultGetFormat [as _getFormat] (internal/modules/esm/get_format.js:71:15)In 7.0.2 the package declares "type": "module" and its bin/tsc file, which has no extension, contains import "../lib/tsc.js";. Node 12.17.0 and 14.21.3 refuse to load that file; Node 20.20.2 ran the same install and printed Version 7.0.2. TypeScript 7.0.2 declares node >=16.20.0 anyway, so the fix is the same: move to a current Node LTS. On Node 14.17 or later, TypeScript 6.0.3 is the newest major whose range still includes Node 14, and it compiled the test file on Node 14.21.3.
Through npx, npm 6 hides the stack#
When TypeScript 5.1.6 is a local devDependency on Node 12.17.0, npx tsc hello.ts with npm 6.14.4 printed only one line:
Unexpected token '?'There is no file name or line number, so it is easy to mistake for a syntax error in your own code. The cause and the fix are the same as above.
"I upgraded Node and it still fails"#
The question's author had tried installing the latest Node and still got the error, and the third answer reports the same with Node 18. As a control, TypeScript 5.1.6 on Node 18.20.8 compiled the test file and printed Version 5.1.6. A Node 18 process does not raise this error. If you see it after an upgrade, the node that runs tsc is still an old copy: a second installation earlier in PATH, a version manager that was not switched in this terminal, or an editor or CI job with its own Node. Running node -v in the same context as the failing command settles it. In CI, set the Node version in the workflow itself; the same habit avoids Next.js refusing to build on an old Node.
Once tsc runs on a supported Node, any remaining errors are about your code and configuration. Readers moving all the way to TypeScript 6 should check the compiler option changes in the TypeScript 6.0 migration notes, since strict mode becomes the default and classic module resolution is removed there. In short, the ?? error is never fixed inside the .ts file: the Node that runs tsc and the TypeScript version you install have to support each other.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix TS2688: node_modules Is the Wrong typeRoots
Reproduce the broad typeRoots mistake, distinguish it from missing @types packages, and preserve custom global declarations while repairing tsconfig.
Fix Cannot find name 'AbortSignal' in axios typings
Which axios releases trigger TS2304, why upgrading axios no longer clears it, and the tsconfig fixes reproduced on TypeScript 4.5.2 and 7.0.2.
Fix Cannot find name 'console' in TypeScript (TS2584)
console.log fails to type-check in a Node project. See which two tsconfig settings hide console, why the compiler hint points the wrong way, and the fix.


