Why isn't try catch blocks catching exceptions - javascript

So I have this piece of code that works fine, but if there is an error with the data type the try catch blocks are not working. It appears I am going to have to check all data types before using them to ensure my server doesn't crash.
For instance in the following code, If tokens for some reason wasn't an array, when the error get's thrown, my try catch isn't catching the error. Instead it is crashing the server.
router.patch("/updateDeviceToken", checkIfAuthenticated, (req, res) => {
try {
console.log("In updating contacts");
console.log("body", req.body);
User.findById(req.authId, (error, user) => {
try {
if (error) {
console.log(error);
console.log("user found");
return res.status(404).json(error);
}
if (!user) return res.status(401).json("User not found");
if (
req.body.android &&
!user.tokens.android.includes(req.body.android)
) {
user.tokens.android.push(req.body.android);
user
.save()
.then((user) => {
console.log("token updated");
return res.json("Token updated");
})
.catch((error) => res.status(404).json(error));
} else if (req.body.iOS && !user.tokens.iOS.includes(req.body.iOS)) {
user.tokens.iOS.push(req.body.iOS);
user
.save()
.then((user) => {
console.log("token updated");
return res.json("Token updated");
})
.catch((error) => res.status(404).json(error));
} else {
console.log("token received but not updated");
return res.json("Token received but not updated");
}
} catch (e) {
console.log(e);
return res.status(404).json("There was an error");
}
});
} catch (e) {
console.log(e);
}
});

try catch doesnt work well with then
Can you change code to use promises with await / async ?
You can use try catch with it

I struggled with that as it is easily overlooked in the documentation but For errors returned from asynchronous functions invoked by route handlers and middleware, you must pass them to the next() function, where Express will catch and process them. For example:
app.get('/', function (req, res, next) {
fs.readFile('/file-does-not-exist', function (err, data) {
if (err) {
next(err) // Pass errors to Express.
} else {
res.send(data)
}
})
})
You can also write your custom error handler, long read but it will save you a lot of time.

Related

fetch catch return Unexpected token U in JSON at position 0

i try to throw error message but it throw me this message : (use React and NodeJS)
return SyntaxError: Unexpected token U in JSON at position 0
fetch("http://localhost:3000/api/register", options)
.then(response => response.json())
.then(user => {
alert('Registration successful !')
this.props.history.push("/");
})
.catch(err => {
console.error(err)
console.log(err.message)
});
}
server side :
router.post('/', async (request, response) => {
try {
const user = request.body;
const newUser = await registerLogic.addUser(user);
if (newUser === 0) {
throw "User name already exists";
}
if(newUser === 1){
throw "Something is missing";
}
response.status(201).json(newUser);
} catch (error) {
console.log(error);
response.status(500).send(error);
}
});
The error Unexpected token U in JSON at position 0 tells you pretty much what's going on here: the first character of the JSON you’re trying to parse is literally a “U”.
Looking at your server-side code, you’re throwing an error “User name already exists”, catching that error, and then returning that message as the response body. Unfortunately, it's not valid JSON, hence the error.
Instead try returning a valid JSON response by updating your catch statement like this:
try {
// ...
} catch (error) {
response
.status(500)
.send(JSON.stringify({ error }));
}
Your response is not json, in your catch block return json response.
} catch (error) {
console.log(error);
response.status(500);
response.json({ message: error.message })
}
In your fetch, check status code returned from the backend.
fetch("http://localhost:3000/api/register", options)
.then(response => response.json())
.then(user => {
if (user.status !== 200) {
alert('ERR', user);
return;
}
alert('Registration successful !')
this.props.history.push("/");
})
.catch(err => {
console.error(err)
console.log(err.message)
});
}
The other answers deal with your original issue well. To answer your followup questions
when i do it now it not get the catch and contine to .then and send me success message
Fetch will not reject the promise for failed HTTP status codes. This may be a surprise compared to Angular or jQuery which will. Fetch will only reject the promise for network level errors, connection dropped out etc.
This is stated in the docs
What you can do instead is something like this:
fetch("http://localhost:3000/api/register", options)
.then(async response => {
if (!response.ok)
throw new Error(await response.text());
return response;
})
.then(response => response.json())
.then(user => {
alert('Registration successful !')
this.props.history.push("/");
})
.catch(err => {
console.error(err)
console.log(err.message)
});
It will check for a successful HTTP status code and reject the promise chain with the server response if it was not. You may want to create your own exception extending the Error class rather than throwing it directly.

How to handle async callback promise rejection?

Try to handle every exception in my async code (nodeJS, ExpressJS):
Here is almost pseudo code. I use limiter (npm limiter) module with method removeTokens (num, callback(err,remainingRequest)). Big part of code is inside the callback, and I wanna catch and throw any error there to the handler, but for now the error inside callback is still marked as "unhandled exception" and I don't understand why.
app.post('/', async (req, res) => {
try {
...
return getAll();
async function getAll () {
limiter.removeTokens(1, async (err, remainingRequest) => {
try {
throw new Error('THROWN')
} catch (error) {
throw error
}
})
}
} catch (error) {
console.log(error);
}
});
You shouldn't pass async functions into things that don't expect them (unless you catch all errors, as you are with your app.post callback). Instead, give yourself a wrapper for limiter.removeTokens that returns a promise:
function removeTokens(limiter, id) {
return new Promise((resolve, reject) => {
limiter.removeTokens(id, (err, remainingRequest) => {
if (err) {
reject(err);
} else {
resolve(remainingRequest);
}
});
});
}
(You might also look into util.promisify for that.)
Then:
app.post('/', async (req, res) => {
try {
...
await getAll(); // *** Or you might just use `removeTokens(limiter, 1)` directly here
function getAll() {
return removeTokens(limiter, 1);
}
} catch (error) {
console.log(error);
}
});
Here it is using removeTokens directly:
app.post('/', async (req, res) => {
try {
...
await removeTokens(limiter, 1);
} catch (error) {
console.log(error);
}
});
Firstly if possible please share as much code as you can as then it is easy for us to debug where the problem might be.
Coming you your question i think the problem is that in your try..catch block you are throwing the error instead of handling it with a reject. Below i have pasted a code block which you can try and let me know if it works for you. Please not the syntax might be different but the idea is that you have to reject the Promise in case of error.
`````````limiter.removeTokens(1, async (err, remainingRequest) => {
````````````try {
```````````````throw new Error('THROWN')
````````````} catch (error) {
```````````````return Promise.reject(error) //
````````````}
`````````})
``````}
```} catch (error) {
``````console.log(error);
```}
})

Promise not returning any data for fetch return

I´m building an express router that uses mongoose to access the database. My current problem relies on this piece of code:
app.use("/authreset", (req, res) => {
authenticator
.resetPassword(
req.body.username,
req.body.password,
req.body.token,
req.body.type
)
.then((response, error) => {
if (error) throw new Error(error);
console.log('*****************');
console.log(response);
if (!response) {
res.sendStatus(401);
return;
}
})
.catch(error => {
console.log('*****************');
console.log(error);
if (error) throw new Error(error);
});
});
resetPassword uses the following mongoose call:
return UserModel
.findByIdAndUpdate(user.id, data, { new: true })
.exec();
For some reason, my route is being called and the response is fine (checked on console.log(response) inside promise).
My problem is that the response is never sent back to the client, that times out the fetch call.
Why is my promise not returning data?
Uh, you log the response, but you never send it (or at least respond with a status code)?
Your code should look more like
app.use("/authreset", (req, res) => {
authenticator.resetPassword(
req.body.username,
req.body.password,
req.body.token,
req.body.type
).then(response => {
console.log(response);
if (!response) {
return res.sendStatus(401);
} else {
return res.sendStatus(200); // <<<
}
}, error => {
console.log(error);
return res.sendStatus(500);
});
});
Notice that the then callback never gets called with more than one argument, so that error you were checking for cannot happen. In the catch handler, you should never rethrow an error if it doesn't get handled further down. Also I changed .then(…).catch(…) to the more fitting .then(…, …).

How to throw exception for sync callback in nodejs?

I want to throw an error exception for an redis.set callback and catch in try-catch block and then get control to error handling express middleware.
try {
redis.get('key', (err, reply) => {
if(err) throw err;
if(!reply) throw new Error('Can't find key');
});
}
catch{
next(error);
}
the problem is, that try-catch is simply not working, error is going to node console, but server is responding with 200 status.
You cant catch async events. Use promises for that:
const getKey = new Promise((res,rej) => {
redis.get('key', (err, reply) => {
if(err) return rej(err);
res(reply);
});
});
So one can do:
getKey.catch(next);
getKey.then(reply => {
//do whatever
next();
});

Chaining promises with then and catch

I'm using the bluebird Promise library. I'd like to chain promises and catch specific promises errors. Here's what I'm doing :
getSession(sessionId)
.catch(function (err) {
next(new Error('session not found'));
})
.then(function (session) {
return getUser(session.user_id);
})
.catch(function (err) {
next(new Error('user not found'));
})
.then(function (user) {
req.user = user;
next();
});
But if an error is thrown by getSession, the two catch are called, as well as the second then. I'd like to stop the error propagation at the first catch, so that the second catch is only called when getUser throws, and the second then when getUser succeeds. What do?
The promise that is returned by the .catch method will still be resolved with the result of the callback, it doesn't just stop the propagation of the chain. You will either need to branch the chain:
var session = getSession(sessionId);
session.catch(function (err) { next(new Error('session not found')); });
var user = session.get("user_id").then(getUser);
user.catch(function (err) { next(new Error('user not found')); })
user.then(function (user) {
req.user = user;
next();
});
or use the second callback to then:
getSession(sessionId).then(function(session) {
getUser(session.user_id).then(function (user) {
req.user = user;
next();
}, function (err) {
next(new Error('user not found'));
});
}, function (err) {
next(new Error('session not found'));
});
Alternatively, the better way would to just propagate the errors through the chain, and call next only in the very end:
getSession(sessionId).catch(function (err) {
throw new Error('session not found'));
}).then(function(session) {
return getUser(session.user_id).catch(function (err) {
throw new Error('user not found'));
})
}).then(function (user) {
req.user = user;
return null;
}).then(next, next);
Since you're using bluebird for promises, you actually don't need a catch statement after every function. You can chain all your thens together, and then close the whole thing off with a single catch. Something like this:
getSession(sessionId)
.then(function (session) {
return getUser(session.user_id);
})
.then(function (user) {
req.user = user;
next();
})
.catch(function(error){
/* potentially some code for generating an error specific message here */
next(error);
});
Assuming the error messages tell you what the error is, it's still possible to send an error specific message like 'session not found' or 'user not found', but you'll just have to look into the error message to see what it gives you.
Note: I'm sure you probably have a reason for calling next regardless if there's an error or not, but it might be useful to throw in a console.error(error) in the case that you get an error. Alternatively, you could use some other error handling function, whether it's a console.error, or res.send(404), or something of the like.
I am using it like that:
getSession(x)
.then(function (a) {
...
})
.then(function (b) {
if(err){
throw next(new Error('err msg'))
}
...
})
.then(function (c) {
...
})
.catch(next);

Categories

Resources