Hapi.js UnhandledPromiseRejectionWarning: Error: reply interface called twice? - javascript

when I running my project, I get the error:
(node:5795) UnhandledPromiseRejectionWarning: Error: reply interface called twice
at Object.exports.assert (/Users/labikemmy/Downloads/React-Native-FriendChat/api/node_modules/hoek/lib/index.js:736:11)
at Function.internals.response (/Users/labikemmy/Downloads/React-Native-FriendChat/api/node_modules/hapi/lib/reply.js:164:10)
at bound (domain.js:301:14)
at Function.runBound (domain.js:314:12)
at reply (/Users/labikemmy/Downloads/React-Native-FriendChat/api/node_modules/hapi/lib/reply.js:72:22)
at bound (domain.js:301:14)
at runBound (domain.js:314:12)
at result.then (/Users/labikemmy/Downloads/React-Native-FriendChat/api/node_modules/hapi/lib/handler.js:105:36)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
(node:5795) 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(). (rejection id: 1)
(node:5795) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
null
I don't know it is bug or my code error? I'm screen hapi.js issues, and someone said the error is bug, another said 'reply() times is limit in same request'? if it is limited, how to change the code at below?
```
export default async function (request, reply) {
if (request.auth.credentials.email !== request.payload.email) {
await User.findOne({ email: request.auth.credentials.email }).then(
(user) => {
if (user) {
User.findOne({ email: request.payload.email }).then(
(friend) => {
if (friend) {
const stringId = `${friend._id}`;
const friendExists = user.friends.filter(f => `${f}` === stringId).length > 0;
if (!friendExists) {
user.friends.push(friend);
user.save();
reply({ friend: { fullName: friend.fullName, _id: friend._id } });
} else {
reply(Boom.conflict('You have added already this friend'));
}
} else {
reply(Boom.notFound(`Friend ${request.payload.email} doesn't exist`));
}
},
);
} else {
reply(Boom.notFound('Cannot find user'));
}
},
);
} else {
reply(Boom.conflict('Cannot add yourself as a friend'));
}
}
Hapi#16.4.1

Do you have any other plugins or lifecycle hooks like onPreHandler or something? Maybe there is some point your code that throws this error because you (or your code somehow) are calling reply interface before your actual response.
Also, I refactored your code. You are already utilizing JavaScript async interface, so you don't need to put "then" calls to your promises.
Try this and watch that what will come out:
export default async function (request, reply) {
if (request.auth.credentials.email === request.payload.email) {
return reply(Boom.conflict('Cannot add yourself as a friend'))
}
// I belive this is mongoose model
const user = await User.findOne({email: request.auth.credentials.email}).exec();
if (!user) {
return reply(Boom.notFound('Cannot find user'));
}
const friend = await User.findOne({email: request.payload.email}).exec();
if (!friend) {
return reply(Boom.notFound(`Friend ${request.payload.email} doesn't exist`));
}
const stringId = `${friend._id}`;
const friendExists = user.friends.filter(f => `${f}` === stringId).length > 0;
if (!friendExists) {
// hmmm shouldn't it be friend._id? user.friends.push(friend._id.toString());
user.friends.push(friend);
// better use this statement
// ref: http://mongoosejs.com/docs/api.html#document_Document-markModified
user.markModified('friends');
await user.save();
return reply({friend: {fullName: friend.fullName, _id: friend._id}});
} else {
return reply(Boom.conflict('You have added already this friend'));
}
}

Related

QuerySnapshot.empty causes a promise rejection error

I have a back-end using firebase-admin and express to allow post requests from the client to the server to make changes to the firestore I have that contains stuff like user data (this is a test and not a real product). I want to check if a document already exists so a user cannot register with that username again. I have first seen instances of doc.exists but that returns undefined for me and I looked into the documentation and found doc.empty which is said to check if a document is empty. I tried it but it returned a promise rejection error. If I changed that line to .exists or to something else, that goes away so I have narrowed down the issue to that line.
index.js (backend)
app.post("/registeruser", function (req, res) {
res.setHeader("Content-Type", "application/json");
try {
const username = req.body.username;
const password = req.body.password;
const passwordEncrypted = HmacSHA1(password, JSON.parse(fs.readFileSync("./keys.json"))["passwordEncryptKey"]).toString();
// console.log(username, password, passwordEncrypted);
try {
firestore.collection("users").get(username).then(function (data) {
if (data.empty == false) {
throw [true, "Already registered user!"];
}
}).catch(function (error) {
throw [true, error];
});
if (username == "") {
firestore.collection("users").add({
username: v4(),
passwordhash: passwordEncrypted,
email: "example#gmail.com",
}).then(function () {
return res.status(200).send(JSON.stringify({
error: false,
message: "Successfully registered user!",
}))
}).catch(function (error) {
throw [true, error];
});
}
else {
firestore.collection("users").doc(username).set({
username: username,
passwordhash: passwordEncrypted,
email: "example#gmail.com",
}).then(function () {
return res.status(200).send(JSON.stringify({
error: false,
message: "Successfully registered user!",
}));
}).catch(function (error) {
throw [true, error];
});
}
}
catch (error) {
throw [true, error];
}
}
catch (error) {
console.log(error);
const [isError, errorMessage] = error;
return res.status(404).send(JSON.stringify({
error: isError,
message: errorMessage,
}));
}
});
Terminal Output
(node:29448) UnhandledPromiseRejectionWarning: [object Array]
(node:29448) 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 terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:29448) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
You have multiple concurrent promise chains, and some of those can fail independently. You need to consolidate all your logic into one promise chain.
return firestore.collection("users").get(username)
.then((data) => {
if (data.empty == false) {
throw [true, "Already registered user!"];
}
})
.then(() => {
if (username == '') {
return firestore.collection("users").add({/* Your data */});
}
return firestore.collection("users").doc(username).set({/* Your data */});
})
.then(() => {
return res.status(200);
})
.catch((err) => {
return res.status(500);
});
You can also try using async/await which will significantly simplify logic like this.

How do you solve the "Cannot set headers after they are sent to the client" error in node js?

I've rewritten the following function about 6 different times and am still getting a "Cannot set headers after they are sent to the client" error. I have found several posts on the topic of promises but still cant figure it out:
Error: Can't set headers after they are sent to the client
Cannot set headers after they are sent to the client
Error: Setting header after it is sent - Help me understand why?
The following function is for a forum and is triggered when a comment is submitted. It check to see that the forum post exists, than if a parent comment exists (in the case it is a subcomment). I am using firestore.
index.js
const functions = require('firebase-functions');
const app = require('express')();
const {postOneForumComment,
} = require('./handlers/forumPosts');
app.post('/forumPost/:forumPostId/:parentId/comment', FBAuth, postOneForumComment);
exports.api = functions.https.onRequest(app);
forumPosts.js
// submit a new comment
exports.postOneForumComment = (req, res) => {
if (req.body.body.trim() === '')
return res.status(400).json({ comment: 'Must not be empty' });
const newComment = {
body: req.body.body,
forumPostId: req.params.forumPostId,
parentId: req.params.parentId
};
db.doc(`/forumPosts/${req.params.forumPostId}`) //check to see if the post exists
.get()
.then((doc) => {
if (!doc.exists) {
return res.status(404).json({ error: 'Post not found' });
}
else if (req.params.forumPostId !== req.params.parentId) { //check to see if the comment is a subcomment
return db.doc(`/forumComments/${req.params.parentId}`) //check to see if the parent comment exists
.get();
}
return "TopLevelComment";
})
.then((data) => {
if (data === 'TopLevelComment' || data.exists) {
return db.collection('forumComments').add(newComment); //post the comment to the database
}
return res.status(500).json({ error: 'Comment not found' });
})
.then(() => {
res.json(newComment);
})
.catch((err) => {
console.log(err.message);
res.status(500).json({ error: 'somethign went wrong' });
});
};
ERROR:
(node:29820) 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(). (rejection id: 1)
(node:29820) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with
a non-zero exit code.
There are two ways of using promises. Either you use the then/catch callbacks or you can use async/await to allow you to write them synchronously.
then/catch method
// Some code before promise
somePromise.then(() => {
// Some code after promise action is successful
}).catch(err => {
// Some code if promise action failed
})
// Some code after promise definition you think should run after the above code
// THIS IS WHAT IS HAPPENING WITH YOUR CODE
async/await method
// Some code before promise
await somePromise;
// Some code after promise action is successful
The latter approach was introduces to avoid the callback hell problem and it seems that's where your error is arising from.
When using callback callbacks you must make sure that nothing is defined after the promise definition else it will run before the promise resolves (Which is counter-intuitive since placing code B after code B should make A run before B)
Your error is because your callbacks are probably running AFTER the response has been sent and express does not allow you to send multiple responses for a request.
You should make sure that where ever res.send or res.json is being called exist within the callback.
This article should help you understand promises much better...
Hope this helps...
For anyone who stumbles upon this here is a working solution using Promise.all to make sure all promises are fulfilled before moving on. It is not the prettiest function and I plan on going back and turning it into an async/await ordeal per #kwame and #Ajay's recommendation... but for now it works.
// post a comment
// TODO: turn into async await function
exports.postOneForumComment = (req, res) => {
if (req.body.body.trim() === '') return res.status(400).json({ comment: 'Must not be empty' });
const newComment = {
body: req.body.body,
createdAt: new Date().toISOString(),
forumPostId: req.params.forumPostId,
parentId: req.params.parentId,
username: req.user.username,
userImage: req.user.imageUrl,
likeCount: 0
};
const parentPost =
db.doc(`/forumPosts/${req.params.forumPostId}`).get()
.then((doc) => {
if (!doc.exists) {
res.status(404).json({ error: 'Post not found' });
return false;
}
return true;
})
.catch((err) => {res.status(500).json({ error: 'something went wrong while checking the post' });});
const parentComment =
req.params.forumPostId === req.params.parentId ? true :
db.doc(`/forumComments/${req.params.parentId}`).get()
.then((doc) => {
if (!doc.exists) {
res.status(404).json({ error: 'Comment not found' });
return false;
}
if (doc.forumPostId !== req.params.forumPostId) {
res.status(404).json({ error: 'Comment is not affiliated with this post' });
return false;
}
return true;
})
.catch((err) => {res.status(500).json({ error: 'something went wrong while checking the comment' });});
Promise.all([parentPost, parentComment])
.then((values) => {
if (values[0] && values[1]) {
return db.collection('forumComments')
.add(newComment)
.then(() => {
res.json(newComment);
});
}
return console.log("there was an error");
})
.catch((err) => {
res.status(500).json({ error: 'somethign went wrong with the submission' });
});
};

Promise and Resolve not working

const { GraphQLServer } = require('graphql-yoga');
const mongoose = require('mongoose');
mongoose.connect("mongodb://localhost/test1");
const Todo = mongoose.model('Todo',{
text: String,
complete: Boolean
});
const typeDefs = `
type Query {
hello(name: String): String!
}
type Todo{
id: ID!
text: String!
complete: Boolean!
}
type Mutation{
createTodo(text:String!): Todo
}
`
const resolvers = {
Query: {
hello: (_, { name }) => `Hello ${name || 'World'}`,
},
Mutation:{
createTodo: async (_,{ text }) => {
const todo = new Todo({text, complete: false});
await todo.save();
return todo;
}
}
};
const server = new GraphQLServer({ typeDefs, resolvers })
mongoose.connection.once("open", function() {
server.start(() => console.log('Server is running on localhost:4000'))
});
Hello I'm new to node js and mongoDB. I'm trying to start my server but it's not starting. Every time it shows a error like this:
(node:17896) 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(). (rejection id: 1)
(node:17896) [DEP0018] DeprecationWarning: Unhandled promise rejections are
deprecated. In the future, promise rejections that are not handled will
terminate the Node.js process with a non-zero exit code.
Every time this is showing some promise error.Can anyone please help me to debug this program. I m a beginner. I don't know much of it. But as per my understanding, I have written correct code only.
Probably your save function throws an arrow which you don't handle it!
you can solve this issue with one of these ways:
GraphQL handles promise by itself, so this would give you same result:
createTodo: (_,{ text }) => {
const todo = new Todo({text, complete: false});
return todo.save();
}
using try catch would give you better error handling:
createTodo: async (_,{ text }) => {
const todo = new Todo({text, complete: false});
try {
await todo.save();
return todo;
} catch(err) {
\\ do something with error
console.error('error=>', err);
return null;
}
}

Where can I get the file name and line number of a node warning?

I get these cryptic lines here:
DEBUG: Mongoose connected (node:5983)
UnhandledPromiseRejectionWarning: Unhandled promise rejection
(rejection id: 1): TypeError: Cannot read property 'then' of undefined
(node:5983) [DEP0018] DeprecationWarning: Unhandled promise rejections
are deprecated. In the future, promise rejections that are not handled
will terminate the Node.js process with a non-zero exit code.
How can I get useful debugging information so I don't have to guess where the exact issue is?
I believe it is somewhere in this file:
const mongoose = require('mongoose');
const helper = require('../config/helper');
const schema = require('./Schemas')
mongoose.connect(helper.getMongoose()).then(
() => {
console.log('DEBUG: Mongoose connected')
mongooseConnected();
},
(err) => {
console.log('DEBUG: Mongoose did not connect')
}
);
function mongooseConnected () {
makeSchema( schema.User,
{ id_google: '1',
type: 'person',
timestamp: Date.now()
});
}
function makeSchema (Schema, dataObj) {
const Class = mongoose.model('Class', Schema);
const Instance = new Class(dataObj);
Instance.save((err, results)=>{
if (err) {
return console.error(err);
}
}).then(() => {
console.log('Saved Successfully')
});
}
In your case you are providing a callback to your save function, this way mongoose will not return a Promise:
Instance.save((err, results)=>{
if (err) {
return console.error(err);
}
console.log('Saved Successfully')
})
If you still want to use Promise then you don't have to pass a callback function:
Instance.save().then(() => {
console.log('Saved Successfully')
}).catch(err => {
return console.error(err);
});
In general an unhandled Promise rejection means that you're missing a catch method to deal with the error. Simply including .then() after returning a promise only deals with the code if it runs successfully, whereas including a .catch block will skip .then and only run .catch, with the error as a callback when an error occurs while executing the code which returns the promise.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
myModel.save()
.then(() => {
console.log('Saved');
})
.catch(err => {
console.log(err);
}

Express route hanging async await

I am converting my application to use async/await instead of callbacks for query request made on the backend. It's been going good so far, but I am on a bit of a snag. My page is hanging on getting a get route and not rendering the ejs page. The console from the server also displays,
(node:7036)
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: qryFindLocalID is not defined
(node:7036) .
[DEP0018] DeprecationWarning: Unhandled promise rejections are depreca
ted. In the future, promise rejections that are not handled will terminate the Nod
e.js process with a non-zero exit code.
Any help would be appreciated.
The code so far is,
router.get("/secure", async (req, res) => {
let user = req.session.passport.user;
try {
if (user.chkUserStatus) {
if (user.lWaterLabID == 0 || user.lWaterlabID == -9999) {
// in both cases sLabID is set to 0
// assign the correct value for sLabName
user.sLabName = user.lWaterLabID == 0 ? "Site Admin" : "Uber Admin";
} else {
let labName = await request.query(
"Some Query"
);
user.sLabName = labName[0].sLabName;
}
} else {
// Houston we've got a problem ...
// user.chkUserStatus is not truthy
req.flash("loginMessage", "User Status is invalid.");
res.redirect("/");
}
const qryFindLocalID = await request.query(
`Some Query`
);
if (user.lWaterLabID == 0) {
const listRecentReports = await request.query(Some Query);
} else {
const listRecentReports = await request.query(Some Query);
}
} catch (err) {
// ... error checks
}
res.render("secure/index", {
qryFindLocalID: qryFindLocalID,
user: user,
listRecentReports: listRecentReports
});
});
The error message talks about an unhandled promise, but that's just wrapping the actual error, which is: ReferenceError: qryFindLocalID is not defined.
So where are you using qryFindLocalID? Ah, right at the bottom in the res.render call.
res.render("secure/index", {
qryFindLocalID: qryFindLocalID,
user: user,
listRecentReports: listRecentReports
});
Now why is qryFindLocalID undefined here? You defined it above in the try-catch block. But there's your problem -- You used const, so qryFindLocalID only exists in the try-catch. Outside of that, it doesn't exist.
You can fix that by using var in the try-catch (var is scoped to the function), or define qryFindLocalID using let ABOVE the try-catch.

Categories