JavaScript errors not showing up in console? - javascript

fields is undefined in the following code snipped, but it is not logged to the console when the error happens. In this specific instance, why, and what is the de facto way to handle this?
"Testing" is logged to the console (Line #2), but the undefined variable fields (Line #4) is not being reported. The error is returned in an API response (Line #5) but with no relevant information such as line #, stack trace, etc.
How can I make errors like this log to the console, and why are they not?
export function post(req, res) {
console.log("Testing")
User.create( getFields(req, ["name_first", "name_last"]) )
.then(user => respondJSON (res, fields, { status: 201 }))
.catch(err => respondError (res, err))
}
Since the catch is responding with an error, I get the following API response:
{
"error": true,
"data": {
"message": "fields is not defined"
}
}
I am using Babel 6 and babel-node to run my code through NPM scripts. I am using morgan logging as well. Removing the middleware for logging does not alter the error output.

The automatic logging to console is a mechanism for unhandled exceptions. Because Promises automatically catch exceptions in the callbacks, the exceptions are no-longer unhandled, so nothing will be automatically logged.
If you want it to be logged, you could perhaps add a throw err at the end of your catch block. This will convert it into an unhandled promise rejection, which is typically handled similarly to an unhandled exception.

Because you didn't actually log the error?
export function post(req, res) {
console.log("Testing")
User.create( getFields(req, ["name_first", "name_last"]) )
.then(user => respondJSON (res, fields, { status: 201 }))
.catch(err => {
console.error(err);
respondError(res, err);
});
}

I had a similar problem caused by a 'finally' which was appended to the main async function running.
run()
.finally(()=>{process.exit(0)})
modifying it to:
run()
.catch(err => {console.log(err)})
.finally(()=>{process.exit(0)})
solved the problem

Related

Mongoose bulk insert misses critical information

The picture above shows an example of a request getting sent to the following route:
and the following picture shows what have been inserted to the database in compass (notice how there are three entries):
As we know, Model.create() accepts an array of objects, or an object.
In this example, I am sending an array of objects, to insert them.
Model.create([]) will insert the documents one by one to the database, it doesn't skip the validation part, which is why I chose it.
and when it finds a document with a validation error, it skips it, and moves to the next one.
until it finishes, then it reports the errors it encounters.
That's what it should be, However it's not exactly working like that.
Note that I have two documents which holds validation errors:
However, mongoose is only reporting the first one, it's not reporting the second one, even though it passes by it, and it sees it.
Why this information is critical?
Because on the client side, I have to know which documents got inserted, and which did not.
In this case, (when I will know which are the ones got inserted and the ones that did not), I can show the client for example that the documents x, y, z has been inserted, while the documents f, g, h did not. So the user can correct his mistake and send the request again.
The current error report is useless, because it only tells "there was a validation error", but it doesn't tell you the "where"
The error report should include all the documents which refused to be written to the database in an array.
Update
I realized that
const data = await User.insertMany(req.body)
Has exactly the same behavior.
It doesn't only apply to Model.create().
Model.insertMany() has the same problem as well.
How to make mongoose report the full errors?
since we don't have a fold code option yet, I will include the code shown in the images, down here. and I hope this isn't going to polute the question.
mongoose.connect('mongodb://localhost:27017/temp', (err) => {
if (err) return log.error(log.label, 'an error occured while connecting to DB!')
log.success(log.label, 'Successfully connected to the database!')
})
app.use(express.json())
app.post('/users', async (req, res, next) => {
try {
const data = await User.collection.insertMany(req.body)
res.json({
message: 'success!',
data,
})
} catch (error) {
console.log(error)
res.json({
message: 'an error',
data: error,
})
}
})
I checked the source code of create() method. It indeed only saves the first error and not all the errors.
However, since the create() method will send one request for each item anyway, you can implement your own logic where you will wrap all the items with Promise.allSettled() and use the create() method for each item. That way, you will know exactly which item was successfully added, and which threw an error:
app.post('/users', async (req, res, next) => {
try {
const items = req.body;
const results = await Promise.allSettled(
items.map((item) => User.create(item))
);
constole.log(results.map((result) => result.status);
// Items that were successfully created will have the status "fulfilled",
// and items that were not successfully created will have the status "rejected".
return res.status(200).json({ message: 'success', results })
} catch (error) {
console.log(error)
return res.status(400).json({ message: 'an error', data: error })
}
})
Just want to draw your attention to insertMany issue-5337 which is similar to your question, they resolved it differently, like below:
Comment on issue: https://github.com/Automattic/mongoose/issues/5783#issuecomment-341590245
In hind sight, going to have to punt on this one until a later release because we need to return a different structure if rawResult is false. We can't just return a ValidationError like in #5698 because that would cause a promise rejection, which isn't correct with insertMany() with ordered: false because that's very inconsistent with how the driver handles it. Using rawResult: true is the way to go right now.
ordered: false should give you multiple validation errors, but if ordered is not set (true by default) we should fall back to the current behavior.
User.collection.insertMany(req.body, { rawResult: true, ordered: false })
.then(users => {
console.log(users)
})
.catch(err => {
console.log(`Error: ${err}`);
});
Console Print:
{
acknowledged: true,
insertedCount: 3,
insertedIds: {
'0': new ObjectId("63a09dcaf4f03d04b07ec1dc"),
'1': new ObjectId("63a09dcaf4f03d04b07ec1de")
'2': new ObjectId("63a0a0bdfd94d1d4433e77da")
},
mongoose: {
validationErrors: [
[
Error: WASetting validation failed: ....
at ValidationError.inspect (...)
...
errors: { itemId: [ValidatorError] },
_message: '.....'
],
[
Error: WASetting validation failed: ....
at ValidationError.inspect (...)
...
errors: { itemId: [ValidatorError] },
_message: '....'
]
]
}
}
You can see the above response, this is not giving which object failed.
Currently, I would suggest #NeNaD's solution.

How to handle a Fatal connection Error in node

I am attempting to make a connection to a MySQL database using Express and Mariadb. The IP for the database changes while I move the PI that it is connected to from the office to my Home. If I don't change the IP before hand then it obviously can not connect to the database, this is fine and a known issue but I want to be able to handle this error without having Node throw a fatal error and shut down
app.get("/db", (req, res) => {
console.log("ping to db!")
MariaPool.getConnection()
.then((conn) => {
conn.query("SELECT * FROM devTable")
.then((data) => {
console.log(data)
res.json(data)
})
.catch((error) => {
console.log("Poor SQL format")
})
.finally(() => {
conn.end()
})
})
.catch((error) => {
console.log("No connection")
res.json({
err: error
})
})
});
Above I attempt to make a connection to the Database, when the IP is wrong it goes to the catch block and logs No Connection as it should, however afterwards a second fatal error is thrown
text: 'Connection timeout: failed to create socket after 1002ms',
sql: null,
fatal: true,
errno: 45012,
sqlState: '08S01',
code: 'ER_CONNECTION_TIMEOUT'
this causes the Node server to shutdown. Try as I may I am unable to find a way to handle this error.
My initial thought is to somehow stop the attempts to make the socket creation once it goes into the catch block but I'm not sure if that is possible.
I've taken a look at This Question but app.use does not solve my problem
Tried the implementation of my own Promise as documented in this question and it still does not handle the fatal error
To sum it up, is it possible to handle fatal errors such as this to allow the program to continue?

how to write/throw errors in javascript web development?

I understand, we can use try and catch block for catching any runtime errors, see code sample below.
I am new to async/await coding paradigm, but I'm assuming, there is no issue with how i catch errors below. I am assuming , if I wanted to throw an error if user is null , in the code below, how do i do that? is that a custom error or can i just do -
if I wanted to catch and rethrow this to some common piece of error handling function/code in my app , how do i do that?
pseudocode
if (user == undefined or null)
throw Error()
var express = require("express");
const models = require("../models");
router.get("/user/", async (req, res) => {
try {
const user = await user.getUser();
res.status(200).send({ ...user.toJSON() });
} catch (err) {
res.status(400).send({ status: false, error: 'something went wrong' ) })
}
});
I dont think the controller is the best place to throw an exception. You can just respond directly with the http error code.
Usually, you throw in the services layer or under ( for exemple in the getUser function ) to break the logic and you assume it will be catched in the controller. In the controller, you can respond with different error code according the error type.
You can do that behavior globaly in your app by making a middleware to map your Errors to the right http Error code.
For example: In getUser, if user === null, throw NotFoundError (custom error extending Error). In the middleware or the controller, if error is instance of NotFoundError, res by a 404.
With express, you can use two optional parameters called next and err, which if you know about express middleware functions, you know that to move to the next function in the middleware pipeline, you use next(). Little do some know that you can use next and err together to pass an error.
So, using the snippet you gave, you can do the following.
const express = require("express");
const models = require("../models");
router.get("/user/", async (err, req, res, next) => {
try {
const user = await user.getUser();
if (!user) {
// use of next and err, will throw error and not exucute
// the rest of the function.
return next(err)
}
res.status(200).send({ ...user.toJSON() });
} catch (err) {
res.status(400).send({ status: false, error: 'something went wrong' ) })
}
});
Personally, I don't like using the implementation shown above, because it is much simpler to let the response in the catch block do the work, but if you really need to handle and error, you can use this method.

How to catch unhandledRejection?

I wrote a Telegram bot using TelegrafJS, this framework wraps the Telegram API. The problem that I'm facing is how to correctly manage the unhandled rejection, in fact when I call this method:
await ctx.deleteMessage(message_id);
where ctx is the instance of TelegrafJS I got:
Bot error: Error: 400: Bad Request: message to delete not found
this error happens 'cause the message_id that I passed no longer exists in Telegram chat. Now, the problem is that I have several controllers which can cause that problem.
I was looking at Promise.prototype.catch(), my question is: can I set up a global rejection handler for my application, or should I use a try/catch block to methods potentially subject to exceptions?
Yes you can, and it is pretty simple:
process.on('unhandledRejection', (err) => {
//handle it!
});
You can also catch the unhandled exceptions, using the same code basically:
process.on('uncaughtException', (err) => {
//handle it!
});
test this code:
bot.use((ctx, next) => {
try {
...
} catch(error) {
next();
}
})
For error handler, you can use:
bot.catch((err, ctx) => {
console.log(err);
return ctx.reply("Error Message");
});

Someone is eating my errors, how can I debug it?

I'm writing a react application using Router1. Here is how the final subscription looks like:
router
.renderResult()
.forEach(() => {
window.ga('send', 'pageview', window.location.pathname);
});
This stream throwing an error (unhandled error), but I don't see it in the console. If I put onError callback in forEach - I can log errors.
If I fix error in stream and create another stream inside, that throws an error, I don't see the message in console:
router
.renderResult()
.forEach(() => {
window.ga('send', 'pageview', window.location.pathname);
Observable.throw(1).subscribe();
});
And even if I replace Observable.throw(1).subscribe(); with simple throw 1 - result is the same, no messages in console and stream is broken.
But If I fix error in the stream, and create another stream that throws an error after some timeout, I see the message "rx.all.js:77 Uncaught 1" which is great.
router
.renderResult()
.forEach(() => {
window.ga('send', 'pageview', window.location.pathname);
setTimeout(() => Observable.throw(1).subscribe(), 1000);
});
So by default rx throws unhandled exceptions, but not in this case, why? Who eating my errors? Any ideas how can I debug it?
So I've found who was eating my tasty errors - superagent#2.0.0. Issue is already fixed and will be released in the next version.
Here is example how you can feed errors to superagent:
import { Observable } from 'rx';
import superagent from 'superagent';
const request = superagent.get('/');
Observable.defer(
Observable.fromNodeCallback(request.end, request, res => res.body)
).subscribe(() => {
throw new Error('tasty error');
});

Categories