-
-
Notifications
You must be signed in to change notification settings - Fork 533
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Node 20: errors produced by reportTSError
are not serialised correctly when using ESM loader
#2026
Comments
I think you're right, the errors are being marshalled from one thread to another, so our Lines 432 to 464 in 7af5c48
Can you think of a good solution here? Is there a way to rehydrate the errors on the main thread so that they're logged correctly? As far as I remember, they errors are never "caught" per-se, they simply have a custom formatting. So when node prints them to stdout, they are formatted the way we want. |
OK, I understand, so it's the correct exception, hence the I had a look at the code in https://github.com/nodejs/node/blob/main/lib/internal/error_serdes.js and I think I see what's happening. The The This means it falls into the try block here https://github.com/nodejs/node/blob/main/lib/internal/error_serdes.js#LL145 which only serialises the The fallback on https://github.com/nodejs/node/blob/main/lib/internal/error_serdes.js#LL150 actually serialises it correctly but it's never reached normally as the block above returns. I tried to change TSError to move this[INSPECT_CUSTOM] = () => {
return this.diagnosticText;
} to the constructor, which caused it to serialise correctly and deserialise to an object with the inspect output of TSError as its inspect output. BUT the output from node is now this:
from this line https://github.com/nodejs/node/blob/main/lib/internal/process/esm_loader.js#L42. I even put I tried to set Any idea what's happening with this? |
reportTSError
are not caught when using ESM loaderreportTSError
are not serialised correctly when using ESM loader
Thanks for filing this issue! I just wanted to mention that it makes debugging the tests running with Node.js's Test Runner ( |
@cspotcode serialisation has been fixed in the nightly version of Node. The problem is that |
@cspotcode Node 20.4 is out now with the serialisation fix in place. Could you please release a new version of //logError.js
import { setUncaughtExceptionCaptureCallback } from "node:process"
setUncaughtExceptionCaptureCallback(console.log)
Unless there's another way of getting this to work that doesn't require the fix in #2025. |
I am using ts-node this way on Node 20 and works. Config
|
I am seeing this with:
And on Mac:
|
Thanks @danrr. This worked for me on node v20.6.1
Full command: |
Wait, that workaround only correctly logs out the error, but the test passes. How do we also fail the test? |
@Pyrolistical your solution doesn't work for me, I get the "Error [ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE]: The Would it be possible to log the error from reportTSError instead of just throwing it? In my case it didn't even produce the diagnosticCodes or a stack trace or even a line where the error occurred. The ts-node process just hang up and printed
It took some non-trivial amount of effort to figure that the problem is related to this bug report. |
@gsimko i gave up trying to use ts-node/esm and just |
I also get this when any TSC error happens under the hood: Restarting 'app.ts server:start'
(node:42858) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./"));'
(Use `node --trace-warnings ...` to show where the warning was created)
node:internal/process/esm_loader:40
internalBinding('errors').triggerUncaughtException(
^
[Object: null prototype] {
[Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]]
}
Node.js v21.1.0
Failed running 'app.ts server:start'
The command is node --watch --loader ts-node/esm app.ts ts-node v 10.9.1 |
The world was not ready for ESM 7 years ago and isn't yet quite ready |
Took me about 20 minutes to come with this solution: // package.json
"scripts": {
"test": "TS_NODE_PROJECT=test/tsconfig.json node --test --import=./test/register.js test/**/*.spec.*"
}, // test/register.js
import { register } from "node:module";
import { pathToFileURL } from "node:url";
import { setUncaughtExceptionCaptureCallback } from "node:process";
setUncaughtExceptionCaptureCallback((err) => {
console.error(err);
process.exit(1);
});
register("ts-node/esm", pathToFileURL("./")); // test/tsconfig.json
{
"extends": "../tsconfig.json",
"compilerOptions": {
"allowImportingTsExtensions": true,
"types": ["node"]
}
} // test/test.spec.ts
import test from "node:test";
import { deepStrictEqual } from "assert";
import { myfn } from "../lib/utils.ts";
test("test array", () => {
deepStrictEqual(myfn([1, 2, 3]), [1, 2, 3]);
}); ESM + TypeScript + node is definitely quite tiresome combination 😅 |
@Kagami unfortunately it's not a solution for real applications, because you can easily land in this fatal error if nothing throws:
|
I switched to https://github.com/swc-project/swc-node because imports without // package.json
"scripts": {
"test": "node --test --import=./test/register.js test/**/*.spec.*"
}, // test/register.js
import { register } from "node:module";
import { pathToFileURL } from "node:url";
register("@swc-node/register/esm", pathToFileURL("./")); Much simpler and also faster. But I'm only using it to run tests... |
For anyone who just wants to see what the TSC errors are without any fanciness, here's how I patched ts-node's class TSError extends Error {
constructor(diagnosticText, diagnosticCodes, diagnostics = []) {
super(`⨯ Unable to compile TypeScript:\n${diagnosticText}`);
this.diagnosticCodes = diagnosticCodes;
this.name = 'TSError';
Object.defineProperty(this, 'diagnosticText', {
configurable: true,
writable: true,
value: diagnosticText,
});
Object.defineProperty(this, 'diagnostics', {
configurable: true,
writable: true,
value: diagnostics,
});
}
} Now I can see the error:
You can use https://github.com/ds300/patch-package for replicating this workaround locally. |
Just doing // logError.js
setUncaughtExceptionCaptureCallback((error) => {
console.error(error);
process.exit(1);
}); |
This is great, thanks for the patch, @alpharder ! Unfortunately, I couldn't get your patch working as-is. Do you think that you could also:
|
After a few research in found the fix in "dist/index.js" l97, he replaced the whole TSError class. |
I also did this research already, but applying the patch the way it is above did not work. So it would be good to get specific instructions. |
|
I just tried |
I believe it's by design. For my use case (unit tests) it's perfect. Also you can check types just by building TypeScript project with |
@ArmorDarks you can use e.g. import process from 'node:process';
process.on('uncaughtException', function (err) {
console.error(err);
process.exit(1);
}); |
I had this error with node 21.7.1 instead of real error:
and i started to get correct error messages after adding this to tsconfig.json (found solution from this thread):
|
Thanks, it works well with my custom loader too 👍 |
Hi All, I have similar experience.
When I ran
I use the I tried to figure it out what is the problem because only the node version changed. After that I moved the ts-node specific setup to the root ts-config.json and run the I don't know what changed but looks like the ts-config resolver starts from the |
transpileOnly is not a solution, then what is the point of using typescript. As for now, stick with node 19. Nothing to do. |
transpileOnly is not the solution. I just wanted to share the ts-config.json resolving logic changed too. |
bump |
Search Terms
Node 20, reportTSError, error
Expected Behavior
When using the
ts-node/esm
loader with Node 18, TS errors are reported correctly. The file below when run withnode --experimental-loader ts-node/esm test.ts
produces the following correct error:
Actual Behavior
On Node 20, the error is serialised to only retain
diagnosticCodes
and no other infoLikely related to https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V20.md#custom-esm-loader-hooks-run-on-dedicated-thread
Steps to reproduce the problem
Run command above on Node 20
Minimal reproduction
TypeStrong/ts-node-repros#33
https://github.com/TypeStrong/ts-node-repros/actions/runs/5057165129/jobs/9075579140
Specifications
and
ts-node v10.9.1
node v20.2.0
TS compiler v5.0.4
package.json:
The text was updated successfully, but these errors were encountered: