With a broken JS file foo.js
that I want to require, contents being:
functon () {
}
A require call yields an error object that if I console.log it, will show:
/Users/rk/Projects/test/foo.js:1
(function (exports, require, module, __filename, __dirname) { functon () {
^
SyntaxError: Unexpected token {
at createScript (vm.js:53:10)
at Object.runInThisContext (vm.js:95:10)
at Module._compile (module.js:543:28)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (/Users/rk/Projects/test/test.js:2:3)
But neither error.message
nor error.stack
contain the filename. Error message above seems to be 3 lines, but when logging error.message
, it only shows Unexpected token {
. I've delved into util's formatting (formatError seems to apply), but I don't see what causes this inconsistent behavior.
I would argue that users who log their own errors should be more capable of seeing which file is broken than is currently the case.
Can anyone explain why this inconsistency exists? I would love to fix this, because it can be a real annoyance to developers.
But neither
error.message
norerror.stack
contain the filename.
The first line of error.stack
is the filename and line number.
This is actually a general problem with SyntaxError: the exception itself does not actually originate within the code but within the internals that tried to parse that code, so the stack trace isn't very helpful (it just tells you how the code was loaded). We ran into similar issues with JS modules in ArangoDB (as of 2.8 our module loader is a slightly modified copy of node's). Special casing the first line of the stacktrace to extract the information that would normally be part of the actual stacktrace is error-prone and TBH quite icky.
In the end we added the same three proprietary properties Mozilla provides (fileName
, lineNumber
and columnNumber
) to all syntax errors we throw instead of adding that information to the error message part of the stacktrace like Node does. This made it easier to extract that information for syntax errors and allows us to use code frames in our error logging.
Can anyone explain why this inconsistency exists?
It's because node goes the extra mile to show a more helpful on-screen error message than what V8 provides by default. If you catch the SyntaxError, you don't get that extra information.
I might be misunderstanding, but the code you posted contains:
at Object.
(/Users/rk/Projects/test/test.js:2:3)
Would you expect Node to catch that and give you the file and line number in the first line rather than the last?
@benjamingr That's where I caught it. It's foo.js
that is broken and nothing tells me that foo.js
is the problem.
@bnoordhuis Do you think there is any way we could add that information to error.message
? Or as @pluma hinted to, adding properties on the error object?
It's there, kind of - it's a private property:
$ node -p '
try {
require("./tmp/broken");
} catch (e) {
var U = process.binding("util");
U.getHiddenValue(e, U.arrow_message_private_symbol);
}
' # prints:
/home/bnoordhuis/src/v1.x/tmp/broken.js:1
(function (exports, require, module, __filename, __dirname) { functon () {}
I'm not against exposing it but it probably needs to be less precooked to be generally useful.
At least you know where to start looking now. :-) See also AppendExceptionLine() in src/node.cc.
Wow, mind blown :) Thanks for sharing, that's the start of a PR 馃憤
Regarding initial confusion, and it's been a few months now, I think I expected the message to contain that /Users/rk/Projects/test/foo.js:1
, but right now it's tacked onto the stack.
In the mean time, what would be the most ideal error representation in the case of a SyntaxError?
We could at least:
.fileName
property.lineNumber
property.columnNumber
propertyWe could also consider reformatting the information in the stack
and message
properties, as the way it's formatted has made the stack a lot harder to parse (if someone were to actually try).
Currently
error.message
Unexpected token var
error.stack
/Users/ronkorving/Projects/node-require-test/syntax-error.js:1
(function (exports, require, module, __filename, __dirname) { var var foo
^^^
SyntaxError: Unexpected token var
at createScript (vm.js:74:10)
at Object.runInThisContext (vm.js:116:10)
at Module._compile (module.js:533:28)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/Users/ronkorving/Projects/node-require-test/test.js:2:3)
Proposal:
error.message
Unexpected token var: var var foo
error.stack
SyntaxError: Unexpected token var
at (/Users/ronkorving/Projects/node-require-test/syntax-error.js:1:5)
at createScript (vm.js:74:10)
at Object.runInThisContext (vm.js:116:10)
at Module._compile (module.js:533:28)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/Users/ronkorving/Projects/node-require-test/test.js:2:3)
Thoughts?
I think I'm -1 to losing this:
/Users/ronkorving/Projects/node-require-test/syntax-error.js:1
(function (exports, require, module, __filename, __dirname) { var var foo
^^^
It also seems like creating Unexpected token var: var var foo
would be error prone.
Given that this has been quiet for almost a year and that there seems to be some argument that the current situation is not a bug, I'm going to close this. Feel absolutely free to re-open or comment if you disagree and you think it might be worked on in the foreseeable future.
Most helpful comment
The first line of
error.stack
is the filename and line number.