Unhandled promise error in Node and Express - javascript

I was making CRUD APIs with NodeJS, ExpressJS, and Mongoose, on executing the following code I got an UnhandledPromiseRejectionWarning error for line number 29. Despite having a try-catch block.
Code:
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
require('../src/db/conn.js');
const MensRanking = require('../src/models/mens.js');
app.use(express.json());
app.get('/', async (req, res) =>{
res.send("<h1>Hello World!</h1>");
})
app.post('/mens', async (req, res) =>{
try{
const addingMensRecords = new MensRanking(req.body);
console.log(req.body);
const insert = await addingMensRecords.save();
res.sendStatus(201).send(insert);
}
catch(e){
res.sendStatus(400).send(e);
}
})
app.get('/mens', async (req, res) =>{
try{
const getMens = await MensRanking.find({});
res.sendStatus(201).send(getMens);
}
catch(e){
res.sendStatus(400).send(e);
}
})
app.listen(port,()=>{
console.log(`\nlistening at http://127.0.0.1:${port}\n`);
})
Error:
(node:20016) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:518:11)
at ServerResponse.header (D:\projects\rest-api-sections\rest-tute\node_modules\express\lib\response.js:771:10)
at ServerResponse.contentType (D:\projects\rest-api-sections\rest-tute\node_modules\express\lib\response.js:599:15)
at ServerResponse.sendStatus (D:\projects\rest-api-sections\rest-tute\node_modules\express\lib\response.js:357:8)
at D:\projects\rest-api-sections\rest-tute\src\app.js:29:13
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:20016) 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:20016) [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.
Here is the complete code repository

You should use res.status instead of sendStatus
Difference between response.status() vs. response.sendStatus() in express
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
require('../src/db/conn.js');
const MensRanking = require('../src/models/mens.js');
app.use(express.json());
app.get('/', async (req, res) => {
res.send('<h1>Hello World!</h1>');
});
app.post('/mens', async (req, res) => {
try {
const addingMensRecords = new MensRanking(req.body);
console.log(req.body);
const insert = await addingMensRecords.save();
res.status(201).send(insert);
}
catch (e) {
res.status(400).send(e);
}
});
app.get('/mens', async (req, res) => {
try {
const getMens = await MensRanking.find({});
res.status(201).send(getMens);
}
catch (e) {
res.status(400).send(e);
}
});
app.listen(port, () => {
console.log(`\nlistening at http://127.0.0.1:${port}\n`);
});

You are using sendStatus function of epxress.js as it immediately sends that particular assigned code to the response object which triggers response before your data is set, so when your send function is called response object has already been sent, hence the error:
Cannot set headers after they are sent to the client
Instead, use this when you need to set HTTP Response codes as well alongside data
res.status(RESPONSE_CODE).send(DATA)

There are two problematic function in this case i just highlight one, because they have the same errors:
app.post('/mens', async (req, res) =>{
try{
const addingMensRecords = new MensRanking(req.body);
console.log(req.body);
const insert = await addingMensRecords.save();
res.sendStatus(201).send(insert);
}
catch(e){
res.sendStatus(400).send(e);
}})
You already sent a response in your try-block with res.sendStatus(201) and trying to send again with .send(insert) -> throws exception
After that you do the same error again with res.sendStatus(400).send(e);
The following code should do what you tried to intend:
app.post('/mens', async (req, res) =>{
try{
const addingMensRecords = new MensRanking(req.body);
console.log(req.body);
const insert = await addingMensRecords.save();
res.status(201).send(insert);
}
catch(e){
res.status(400).send(e);
}})

Related

Error with async code design. UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT],

I am facing an error with node/express. I am assuming the issue is with my asynchronous code design.
Output:
Success in container
Expected Output:
Success in container..
Success in Uploading...
Error: (node:18364) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
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()
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.
Code:
const express = require("express");
const multer = require("multer");
const AuthReq = require("../middleWare/AuthReq");
require("dotenv").config();
const Azure_Storage_Connection_String = process.env.Azure_Connection_String;
const { BlobServiceClient } = require("#azure/storage-blob");
const Router = express.Router();
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads");
},
filename: function (req, file, cb) {
cb(null, Date.now() + "-" + file.originalname);
},
});
const upload = multer({ storage: storage });
Router.post("/profile", AuthReq, upload.single("profile"), async (req, res) => {
const file = req.file;
const blobServiceClient = BlobServiceClient.fromConnectionString(
Azure_Storage_Connection_String
);
const containerName = req.user._id;
const ContainerClient = blobServiceClient.getContainerClient(containerName);
try {
const containerResponse = await ContainerClient.create();
} catch (err) {
return res.status(400).send("Error while sending image");
}
res.send("Success in container");
const contentType = file.mimetype;
const filePath = file.path;
const blobName = file.filename + contentType;
const blockBlobClient = ContainerClient.getBlockBlobClient(blobName);
try {
const uploadBlobResponse = await blockBlobClient.uploadFile(filePath);
} catch (err) {
return res.status(400).send("Error while sending image");
}
res.send("Success in Uploading...");
});
module.exports = Router;
You cannot use res.send more than once per request, because one request has only one response. I assume that you want to send a "two-part" response, so that the user first sees "Success in container" and then (a few seconds later) "Success in Uploading ...".
Node.js will send the response in two "chunks" if you use
res.write("Success in container");
...
res.end("Success in Uploading...");
(See also the explanation in this answer.)

ExpressJS Route Async Middleware

I'm trying to use a middleware in Express but I can't get it to work I get infinite loading time when I make a request. I searched on stackoverflow but I couldn't find any examples that used an async await middleware stored in a separate file. Can someone point me in the right direction?
isAuthenticated.js
const Auth = require('../auth/auth')
const isAuthenticated = async () => {
return async (request, response, next) => {
const token = request.cookies.token;
try {
const JWTVerify = await Auth.verifyJWTToken(token);
next()
} catch (error) {
response.json({ status: "failed", message: "Authentication failed invalid token" });
response.end();
}
}
}
module.exports = isAuthenticated
Server.js
const isAuthenticated = require('./middleware/isAuthenticated')
app.post('/some-route', isAuthenticated, async (request, response) => {
});
You returning a function, and thus the middleware is not passing the request forward.
Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.
check ---> http://expressjs.com/en/guide/writing-middleware.html
const Auth = require('../auth/auth')
const isAuthenticated = async (request, response, next) => {
const token = request.cookies.token;
try {
const JWTVerify = await Auth.verifyJWTToken(token);
next()
} catch (error) {
response.json({ status: "failed", message: "Authentication failed invalid token" });
response.end();
}
}
module.exports = isAuthenticated
I think the issue is the definition of your middleware. You are wrapping it inside a function, but you are not calling it. If you pass it like that to express, express will try to call it but the outer function just returns the inner function. The inner function thus never gets called so next() never gets called.
const isAuthenticated = async (request, response, next) => {
const token = request.cookies.token;
try {
const JWTVerify = await Auth.verifyJWTToken(token);
next()
} catch (error) {
response.json({ status: "failed", message: "Authentication failed invalid token" });
response.end();
}
}

UnhandledPromiseRejectionWarning - UnhandledPromiseRejectionWarning - DeprecationWarning

I am getting this error ->
(node:18420) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'name' of undefined
at C:\Users\ohrid\Desktop\backend2\routes\categories.js:27:24
at Layer.handle [as handle_request] (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:281:22
at Function.process_params (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:275:10)
at Function.handle (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:174:3)
at router (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:47:12)
at Layer.handle [as handle_request] (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:317:13)
at C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:275:10)
at logger (C:\Users\ohrid\Desktop\backend2\node_modules\morgan\index.js:144:5)
(node:18420) 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:18420) [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.
My routes/categories.js:
const { Category } = require('../models/category')
const express = require('express')
const router = express.Router()
router.get(`/`, async (req, res) => {
const categoryList = await Category.find()
if (!categoryList) {
res.status(500).json({ success: false })
}
res.status(200).send(categoryList)
})
router.get('/:id', async (req, res) => {
const category = await Category.findById(req.params.id)
if (!category) {
res.status(500).json({
message: 'The category with the given ID was not found.',
})
}
res.status(200).send(category)
})
router.post('/', async (req, res) => {
let category = new Category({
name: req.body.name,
icon: req.body.icon,
color: req.body.color,
})
category = await category.save()
if (!category)
return res.status(400).send('the category cannot be created!')
res.send(category)
})
router.put('/:id', async (req, res) => {
const category = await Category.findByIdAndUpdate(
req.params.id,
{
name: req.body.name,
icon: req.body.icon || category.icon,
color: req.body.color,
},
{ new: true }
)
if (!category)
return res.status(400).send('the category cannot be created!')
res.send(category)
})
router.delete('/:id', (req, res) => {
Category.findByIdAndRemove(req.params.id)
.then((category) => {
if (category) {
return res
.status(200)
.json({
success: true,
message: 'the category is deleted!',
})
} else {
return res
.status(404)
.json({ success: false, message: 'category not found!' })
}
})
.catch((err) => {
return res.status(500).json({ success: false, error: err })
})
})
module.exports = router
My app.js
const express = require('express')
const app = express()
const morgan = require('morgan')
const mongoose = require('mongoose')
const cors = require('cors')
const dotenv = require('dotenv')
require('dotenv/config')
app.use(cors())
app.options('*', cors())
//middleware
app.use(morgan('tiny'))
//Routes
const categoriesRoutes = require('./routes/categories')
const productsRoutes = require('./routes/products')
const usersRoutes = require('./routes/users')
const ordersRoutes = require('./routes/orders')
const api = process.env.API_URL
app.use(`${api}/categories`, categoriesRoutes)
app.use(`${api}/products`, productsRoutes)
app.use(`${api}/users`, usersRoutes)
app.use(`${api}/orders`, ordersRoutes)
mongoose
.connect(
'mongodb+srv://dani:Luka5678#cluster0.23wee.mongodb.net/e-shop?retryWrites=true&w=majority',
{
useNewUrlParser: true,
useUnifiedTopology: true,
dbName: 'e-shop',
}
)
.then(() => {
console.log('Database connection is ready')
})
.catch((err) => {
console.log(err)
})
app.listen(4000, () => {
console.log('server is running on http://localhost:4000')
})
What should I change?
You don't have any error handling layer in your application.
If you use Express v5 and above, route handlers and middleware that return a Promise will catch the errors and will call next(value) automatically.
Otherwise, from asynchronous functions, you must pass them to the next() function, where Express will catch and process them.
That way, you won't get the UnhandledPromiseRejectionWarning.

Loading express template with a passed variable returns error `Cannot set headers after they are sent to the client`

I have a form and I am trying to validate it with express-validator. When there are no validation errors, I get no error in the console, but when there are validation errors I try to pass them to my EJS template, but it gives me an error in the console. This is my full code:
var express = require('express');
var app = express();
var path = require('path');
var mongoose = require('mongoose');
var bodyParser = require('body-parser')
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}))
const { check, validationResult } = require('express-validator');
app.listen(8080);
// saytin asuma inch template piti ogtagorcvi
app.set('view engine', 'ejs');
// MongoDB
let dbUrl = 'mongodb+srv://grig:xxxXXXxxx#cluster0-osvfl.mongodb.net/test?retryWrites=true&w=majority';
mongoose.connect(dbUrl ,{useNewUrlParser : true},(err) => {
if (err) {
console.log(err);
}
});
var schema = new mongoose.Schema({ name: 'string', message: 'string' });
var User = mongoose.model('User', schema);
//
// router
app.get('/', function(req, res) {
res.render('index');
});
app.use(express.json());
app.post('/send', [
check('name').isLength({ min: 1 }).withMessage('Անունը չի կարող դատարկ լինել'),
check('message').isLength({ min: 10 }).withMessage('Նամակը պետք է լինի 10 սիմվոլից ավել')
], (req, res) => {
// Uxarkel errornery
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.render('index',{
errors: errors
});
}
// Stexcel userin
User.create({
name: req.body.name,
message: req.body.message
}).then(user => res.json(user));
});
//
And here's the error that I'm getting:
(node:6244) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (C:\xampp\htdocs\node\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (C:\xampp\htdocs\node\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\xampp\htdocs\node\node_modules\express\lib\response.js:267:15)
at User.create.then.user (C:\xampp\htdocs\node\server.js:51:23)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:6244) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecti
ng a promise which was not handled with .catch(). (rejection id: 1)
(node:6244) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process wit
h a non-zero exit code.
I'm new to Node, so can you please explain what causes the error. Thanks.
if (!errors.isEmpty()) {
res.render('index',{
errors: errors
});
}
else {
// Stexcel userin
User.create({
name: req.body.name,
message: req.body.message
}).then(user => res.json(user))
}
The else part of code was getting executed, even if there was error, and it was trying to send the response again. thus you were getting that error. Or you can a return when you are sending error, it will resolve the issue.

Using Multer upload function in async mode with nodejs

I need make a conversion of a Multer Midware function('upload') using callback to works in async mode using promises.
I tried to transform the upload function in a promise.
The image sent to server continues being saved as before, but my code throw an error as:
(node:3568) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): undefined
(node:3568) [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.
when I execute the function
var resp=await uploadAsync(req, res);
What am I doing wrong?
//server code
'use strict';
const express = require('express');
const router = express.Router();
const pool = require('./pool'); // my database pool module, using promise-mysql
const Errors = require('./mysql_errors'); // my collection of custom exceptions
const HttpStatus = require('http-status-codes');
var path = require('path')
var fs = require('fs')
const fileDir='./public/images/uploads'
//imagens
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, fileDir)
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname);
}
})
const upload = multer({ storage: storage}).single('foto');
function uploadAsync(req,res){
return new Promise(function(resolve,reject){
upload(req,res,function(err){
if(err !== null) return reject(err);
resolve();
});
});
}
router.post('/foto/:id',uploadAsync, async function(req,res,next){
try{
var resp=await uploadAsync(req, res);
}catch(err) {
return res.status(500).send({ success:false, message: 'Erro', results:{} }); // 404
}
});
module.exports=router;
if(err !== null) return reject(err);
resolve();
in those conditions, you have to keep like
if(err !== undefined) return reject(err);
resolve();
as the error will be undefined is the call back returns true.

Categories

Resources