Exception can't be caught by process.on("uncaughtException") - node.js

I have the following code in index.js
const winston = require('winston');
require('winston-mongodb');
process.on('uncaughtException', (ex) => {
console.log('WE GOT AN UNCAUGHT EXCEPTION');
winston.error(ex.message, ex);
});
Here's how I expect it to work. The index.js will raise an uncaught exception.Then the console.log will print the message and the winston library will log the error and will store it in it's logfile.
In reality however none of the above works.Not even the console.log. So I suppose that the error is never raised.
I use: node -> v10.15.1
npm -> 6.4.1
winston ->2.4.0
winston-mongodb ->3.0.0

Related

Proper way to handle fetch errors in NodeJS v18?

I switched to NodeJS v18 with the built-in fetch and I'm using it as such:
async function get511AK() {
let res = await fetch(URL, { method: 'GET' })
if (res.ok && (res.headers.get('content-type').includes('json'))) {
let data = await res.json();
jsonresponseAK = data;
} else {
console.log("(" + res.url + ') is not json');
}
}
However, sometimes I'm getting a timeout on the URL, which is going to happen, but it's causing the script to exit. I've tried wrapping this in try/catch and it did not prevent it from exiting.
This never happened in Node v12 under the node-fetch library. What else can I add to control those connection timeouts?
node:internal/deps/undici/undici:11118
Error.captureStackTrace(err, this);
^
TypeError: fetch failed
at Object.fetch (node:internal/deps/undici/undici:11118:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Timeout.get511AK [as _onTimeout] (/home/wazebot/dot-scripts/script-relay.js:76:12) {
cause: ConnectTimeoutError: Connect Timeout Error
at onConnectTimeout (node:internal/deps/undici/undici:6625:28)
at node:internal/deps/undici/undici:6583:50
at Immediate._onImmediate (node:internal/deps/undici/undici:6614:13)
at process.processImmediate (node:internal/timers:471:21) {
code: 'UND_ERR_CONNECT_TIMEOUT'
}
}
Node.js v18.12.1
Hope it helped!
process.on('uncaughtException', console.log);
// Uncaught Exception thrown - when you throw an error and did not catch anywhere.
process.on('unhandledRejection', console.log);
// Unhandled Rejection at Promise - similar, when you fail to catch a Promise.reject.

Handle Exceptions in node/express not working

I have a node/express application which I'm trying to catch all exceptions so that the application doesn't just freeze. I created an error by calling a mongoose db when it's not running.
await mongoose.connect(dbUrl, mongooseOptions);
Which gives me the following error then the app crashes
MongoNetworkError: failed to connect to server [localhost:27017] on
first connect
Before that is run, I have the following:
process.on('unhandledRejection', (ex) => {
console.log(ex.name, ex.message);
console.log('UNCAUGHT EXCEPTION! 💥 Shutting down...');
process.exit(1);
});
That unhandled Rejection doesn't seem to run. How can I get it to run on exception?
Use uncaughtException instead of unhandledRejection
process.on('uncaughtException', (ex) => {
console.log(ex.name, ex.message);
console.log('UNCAUGHT EXCEPTION! 💥 Shutting down...');
process.exit(1);
});

Try to cach UnhandledPromiseRejectionWarning discord.js

i'm trying to catch an discord.js error
This error pops up when internet is off, but i want some clean code instead this messy one...
How can i catch this?
I did really try everything..
code:
(node:11052) UnhandledPromiseRejectionWarning: Error: getaddrinfo ENOTFOUND disc
ordapp.com
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:66:26)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:11052) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This
error originated either by throwing inside of an async function without a catch
block, or by rejecting a promise which was not handled with .catch(). To termin
ate the node process on unhandled promise rejection, use the CLI flag `--unhandl
ed-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejecti
ons_mode). (rejection id: 2)
(node:11052) [DEP0018] DeprecationWarning: Unhandled promise rejections are depr
ecated. In the future, promise rejections that are not handled will terminate th
e Node.js process with a non-zero exit code.
i did try this at the very top :
process.on('uncaughtException', function (err) {
//console.log('### BIG ONE (%s)', err);
console.log("555")
});
aswell this one :
client.on('error', error => {
if (error.code === 'ENOTFOUND') {
console.log(no internet!!)
}
});
I also did try this to see where its from, but nothing shows up its still the same
try {
var err = new Error("my error");
Error.stackTraceLimit = infinity;
throw err;
} catch(e) {
console.log("Error stack trace limit: ")
console.log(Error.stackTraceLimit);
}
Error stack trace limit:
10
(node:11008) UnhandledPromiseRejectionWarning: Error: getaddrinfo ENOTFOUND disc
ordapp.com
here is the code i use for now what gives the error.
i just want to catch the error in something like this: (No connection)
const Discord = require('discord.js')
const client = new Discord.Client({ autoReconnect: true });
const opn = require('opn')
const getJSON = require('get-json')
const request = require('request');
const config = require("./config/config.json");
const pushbullet = require("./config/pushbullet.json");
const addons = require("./config/addons.json");
const Registration = require("./config/Reg.json");
client.on('uncaughtException', function (err) {
//console.log('### BIG ONE (%s)', err);
console.log("555")
});
client.login(config.Settings[0].bot_secret_token);
I would try to wrap it with try/catch.
And maybe add the following code to understand better what is happening.
Error.stackTraceLimit = Infinity
Reference:
https://developer.mozilla.org/en-US/docs/Archive/Web/JavaScript/Microsoft_Extensions/Error.stackTraceLimit
Remember to remove it after the problem solved, this is not suitable for production use.
Well i solved it!!
I put this on top and its all solved.
process.on('unhandledRejection', error => {
if (error.code === "ENOTFOUND") { console.log ("No internet connection")}
if (error.code === "ECONNREFUSED") { console.log ("Connection refused")}
//console.log('Unhandled promise rejection:', error.code);
});

How to catch UnhandledPromiseRejectionWarning for GCS WriteStream

Observed Application Behavior
I'm getting a UnhandledPromiseRejectionWarning: Error: Upload failed when using #google-cloud/storage in node.js.
These errors come when processing thousands of requests. It's a small percentage that cause errors, but due to the lack of ability to handle the errors, and the lack of proper context from the error message, it's very difficult to determine WHICH files are failing.
I know in general promises must have a .catch or be surrounded by a try/catch block. But in this case I'm using a write stream. I'm a little bit confused as to where the promise that's being rejected is actually located and how I would intercept it. The stack trace is unhelpful, as it only contains library code:
UnhandledPromiseRejectionWarning: Error: Upload failed
at Request.requestStream.on.resp (.../node_modules/gcs-resumable-upload/build/src/index.js:163:34)
at emitTwo (events.js:131:20)
at Request.emit (events.js:214:7)
at Request.<anonymous> (.../node_modules/request/request.js:1161:10)
at emitOne (events.js:121:20)
at Request.emit (events.js:211:7)
at IncomingMessage.<anonymous> (.../node_modules/request/request.js:1083:12)
at Object.onceWrapper (events.js:313:30)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
My Code
The code that's creating the writeStream looks like this:
const {join} = require('path')
const {Storage} = require('#google-cloud/storage')
module.exports = (config) => {
const storage = new Storage({
projectId: config.gcloud.project,
keyFilename: config.gcloud.auth_file
})
return {
getBucketWS(path, contentType) {
const {bucket, path_prefix} = config.gcloud
// add path_prefix if we have one
if (path_prefix) {
path = join(path_prefix, path)
}
let setup = storage.bucket(bucket).file(path)
let opts = {}
if (contentType) {
opts = {
contentType,
metadata: {contentType}
}
}
const stream = setup.createWriteStream(opts)
stream._bucket = bucket
stream._path = path
return stream
}
}
}
And the consuming code looks like this:
const gcs = require('./gcs-helper.js')
module.exports = ({writePath, contentType, item}, done) => {
let ws = gcs.getBucketWS(writePath, contentType)
ws.on('error', (err) => {
err.message = `Could not open gs://${ws._bucket}/${ws._path}: ${err.message}`
done(err)
})
ws.on('finish', () => {
done(null, {
path: writePath,
item
})
})
ws.write(item)
ws.end()
}
Given that I'm already listening for the error event on the stream, I don't see what else I can do here. There isn't a promise happening at the level of #google-cloud/storage that I'm consuming.
Digging into the #google-cloud/storage Library
The first line of the stack trace brings us to a code block in the gcs-resumable-upload node module that looks like this:
requestStream.on('complete', resp => {
if (resp.statusCode < 200 || resp.statusCode > 299) {
this.destroy(new Error('Upload failed'));
return;
}
this.emit('metadata', resp.body);
this.deleteConfig();
this.uncork();
});
This is passing the error to the destroy method on the stream. The stream is being created by the #google-cloud/common project's utility module, and this is using the duplexify node module to create the stream. The destroy method is defined on the duplexify stream and can be found in the README documentation.
Reading the duplexify code, I see that it first checks this._ondrain before emitting an error. Maybe I can provide a callback to avoid this error being unhandled?
I tried ws.write(item, null, cb) and still got the same UnhandledPromiseRejectionWarning. I tried ws.end(item, null, cb) and even wrapped the .end call in a try catch, and ended up getting this error which crashed the process entirely:
events.js:183
throw er; // Unhandled 'error' event
^
Error: The uploaded data did not match the data from the server. As a precaution, the file has been deleted. To be sure the content is the same, you should try uploading the file again.
at delete (.../node_modules/#google-cloud/storage/build/src/file.js:1295:35)
at Util.handleResp (.../node_modules/#google-cloud/common/build/src/util.js:123:9)
at retryRequest (.../node_modules/#google-cloud/common/build/src/util.js:404:22)
at onResponse (.../node_modules/retry-request/index.js:200:7)
at .../node_modules/teeny-request/build/src/index.js:208:17
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:189:7)
My final code looks something like this:
let ws = gcs.getBucketWS(writePath, contentType)
const handleErr = (err) => {
if (err) err.message = `Could not open gs://${ws._bucket}/${ws._path}: ${err.message}`
done(err)
}
ws.on('error', handleErr)
// trying to do everything we can to handle these errors
// for some reason we still get UnhandledPromiseRejectionWarning
try {
ws.write(item, null, err => {
handleErr(err)
})
ws.end()
} catch (e) {
handleErr(e)
}
Conclusion
It's still a mystery to me how a user of the #google-cloud/storage library, or duplexify for that matter, is supposed to perform proper error handling. Comments from library maintainers of either project would be appreciated. Thanks!

Express Nodejs app crash without error message with nodemon and babel

I have an express nodejs app running with nodemon, however when app crashed, there is no error message logged in console:
Here is my index.js file:
/* eslint-disable */
require("babel-register");
require('./server.js');
I don't think this is a nodemon problem because when I remove babel, console would show error message that 'import' is not defined:
Currently for babel I use
{
"presets": ["env"],
"plugins": [
["transform-runtime", {
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}]
]
}
because of the ReferenceError: regeneratorRuntime is not defined
I tried switching node version, didn't work. Current node version v8.10.0
Would really appreciate if somebody can help me out. It is really a pain to debug without the error message.
for those who encounter the same problem, I ended up solving the problem by this:
/* eslint-disable */
require("babel-register");
try{
require('./server.js');
} catch (e) {
console.log(e)
}
If this still doesn't work, then listen to unhandledRejection and uncaughtException as well by:
process
.on('unhandledRejection', (reason, p) => {
console.error(reason, 'Unhandled Rejection at Promise', p);
})
.on('uncaughtException', err => {
console.error(err, 'Uncaught Exception thrown');
process.exit(1);
});

Resources