The error, verbatim
Jump to the fix ↓node:internal/modules/esm/get_format:189
throw new ERR_UNKNOWN_FILE_EXTENSION(ext, filepath);
^
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for C:\project\src\index.ts
at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:189:9)
at defaultGetFormat (node:internal/modules/esm/get_format:232:36)
at defaultLoad (node:internal/modules/esm/load:145:22) {
code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
Tested on
- Node
- 20.19.4, 22.5.1, 22.6.0, 22.18.0, 24.14.0
- ts-node
- 10.9.2
- tsx
- 4.23.15
- TypeScript
- 5.9.3 and 7.0.2
- OS
- Windows 11 Pro
Contents
The fix
Run your Node version first, because this error disappears on its own from Node 22.18:
node --versionOn Node 22.18 or newer (including Node 24), run the file directly. No loader, no flag, no ts-node:
node src/index.tsOn anything older, install tsx and run the file through it:
npm i -D tsx
npx tsx src/index.tsFor an npm script, or where you need Node’s own flags, load tsx into Node instead:
{ "scripts": { "dev": "node --import tsx src/index.ts" } }Which Node version does what
I ran the same file, unchanged, on five Node versions:
| Node | node src/index.ts |
With --experimental-strip-types |
|---|---|---|
| 20.19.4 | ERR_UNKNOWN_FILE_EXTENSION |
flag doesn’t exist |
| 22.5.1 | ERR_UNKNOWN_FILE_EXTENSION |
bad option |
| 22.6.0 | ERR_UNKNOWN_FILE_EXTENSION |
runs |
| 22.18.0 | runs | runs |
| 24.14.0 | runs | runs |
So there are three eras, and the answer you find online depends entirely on which one it was written in: before 22.6 Node could not load a .ts file at all, from 22.6 it could behind a flag, and from 22.18 it does it by default.
Why it happens
Node decides how to load a file from its extension. In an ES module project, the list is short: .js, .mjs, .cjs, .json, .node and, on new enough versions, .ts, .mts and .cts. Anything else is refused by name before a single line is read, which is why the stack trace points at get_format and never at your code.
Newer Node versions add TypeScript by stripping the types: the type annotations are replaced with whitespace and the result is run as plain JavaScript. Nothing is type-checked and nothing is compiled, which is why it’s fast and also why it can’t handle everything (see the trap below).
Why ts-node hits it too
This is the version most people actually have, because the error arrives from a tool that is supposed to prevent it:
npx ts-node src/index.ts
TypeError: Unknown file extension ".ts" for C:\project\src\index.ts
at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:189:9)
code: 'ERR_UNKNOWN_FILE_EXTENSION'
ts-node hooks into CommonJS loading. The moment your package.json has "type": "module", your .ts file is an ES module, a different loader handles it, and ts-node’s hook is never consulted. Node reaches the extension check and refuses.
Proof it’s the module system and not the file: I removed "type": "module" from package.json and ran the identical command on the identical Node 20, and it printed hello world.
What didn’t work
The trap after the fix
Type stripping is not compilation. Syntax that has to generate JavaScript, like enum and namespace, is refused:
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode
That’s Node 24 running a file whose only crime is one enum. The ways past it, all five variants reproduced: TypeScript enum is not supported in strip-only mode.
Test runners
node --testfollows the same rule asnodeitself: on Node 20 the.tstest file fails, on Node 24 it runs.- Mocha 12 strips types itself, so a
.tstest ran on Node 20 as well, but theenumfile still failed there withERR_UNSUPPORTED_TYPESCRIPT_SYNTAX.
Run it yourself
The project I used is on GitHub, so you can trigger the error on your own machine in under a minute:
git clone https://github.com/nils44344/node-ts-error-repros
cd node-ts-error-repros/01-unknown-file-extension
npm install && npm run repro
How this was tested
A three-line TypeScript file and a package.json with "type": "module", run unchanged on five Node versions installed side by side, with ts-node 10.9.2, tsx 4.23.15, Mocha 12.0.2, and TypeScript 5.9.3 and 7.0.2. Every result above is the actual terminal output, including the failures.
— N.K., end of entry No.013