TypeError: res.status is not a function
Asked Answered
D

9

27

I'm making a function that permits me to upload a picture to imgur in my express API (nodejs), I'm encountering an error when calling a function returning a promise:

TypeError: res.status is not a function
at uploadpicture.then

This is my code: Where error is raised:

  router.post('/upload', (req, res, next)=> { 
    var busboy = new Busboy({headers: req.headers});
    busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
        if(fieldname == 'image') {
            // the buffer
            file.fileRead = [];
            file.on('data', function(data) {
                // add to the buffer as data comes in
                this.fileRead.push(data);
            });

            file.on('end', function() {
                // create a new stream with our buffered data
                var finalBuffer = Buffer.concat(this.fileRead);
                upload = uploadpicture(finalBuffer).then((res)=>{ //success request
                  console.log(res);
                  res.status(200).json({success: true, message: "Successfully uploaded !", url: res.data.link});
                },(err)=>{ //error
                  res.status(500).json({success: false, message: "Error happenned while uploading !"});
                }).catch((error)=>{
                  console.log(error);
                  res.status(500).json({success: false, message: "Error happenned while uploading !"});
                });

            })
        }
    });
    busboy.on('finish', function() {
        //busboy finished
    });
    req.pipe(busboy);
});

And the function :

function uploadpicture(stream){ //get picture stream
    return new Promise((resolve, reject)=>{
    var options = {
      uri: 'https://api.imgur.com/3/image',
      method: 'POST',
      headers: {
          //'Authorization': 'Client-ID ' + config.client_id_imgur // put client id here
      },
      formData: {
          image: stream,
          type: 'file'
      },
      auth: {
        bearer: config.access_token_imgur,
      }
  };
  
  request(options)
      .then((parsedBody)=> {
          resolve(parsedBody);
      })
      .catch((err)=> {
        console.log(err);
        reject(err.toString())
      });
    });
  }
   

The code works perfectly, but I don't know why suddenly this error happened, I tried to:

change arrow functions to function(){}
Add next to the route parameters

Nothing worked.

Directorate answered 3/1, 2020 at 19:31 Comment(0)
S
39

The accepted answer directly addresses the OP's problem, but I post another solution since you can also encounter this error in other places.

When you have:

api.use((error: ErrorRequestHandler, request: ExpressRequest, response: ExpressResponse) => {
  response.status(500).end() // response.status is not a function
})

Because the error handling route must accept 4 arguments for express to identify it as an error middleware.

api.use((error: ErrorRequestHandler, request: ExpressRequest, response: ExpressResponse, next: NextFunction) => {
  response.status(500).end()
})

Just adding the next function (or whatever argument you're missing) will fix it.

https://github.com/visionmedia/supertest/issues/416#issuecomment-514508137

Switchback answered 16/8, 2021 at 12:48 Comment(3)
Very well remembered, although the issue is not about middlewares but it could have a similar issueBeaman
So this error occurs if your code is from the times that app.use accepted 3 parameters instead of 4?Gloriole
close to the docs of app.use, scroll further down to the error-handling..Gloriole
B
19

At this point:

upload = uploadpicture(finalBuffer).then((res)=>{ //success request

the resis the result of promise uploadpicture function (that is the parsedBody), not the res from the express route. So indeed, it has no status function. Try change the then callback name like:

upload = uploadpicture(finalBuffer).then((otherName)=>{ //success request
Beaman answered 3/1, 2020 at 19:36 Comment(2)
Is res a reserved word? I do not get your point. If I use othername it has a status function?Gloriole
actually is not a reserved word. The point is res is the name of the response variable from express route. When he named the promise.then response as res, the .then scope assumes the res is from resolved promise, not from express route. And indeed it has no .status function. Renaming the promise.then res solves the issue, since we usually call res the object from express route. If you prefer to rename the express route object to e.g. otherNameElse, then you would need to call otherNameElse.status function to respond into the route.Beaman
W
7

You are getting this error:

TypeError: res.status is not a function

Because the order should be (err, req, res, next) not (req, res, err, next), example below

const errorHandler = (err, req, res, next) => {
    const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
    res.status(statusCode)
    res.json({
        message : err.message,
        stack :process.env.NODE_ENV === 'production' ? null : err.stack, 
    })
}
Wright answered 2/5, 2022 at 6:6 Comment(0)
G
1

Root cause is

Error-handling middleware always takes four arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don’t need to use the next object, you must specify it to maintain the signature. Otherwise, the next object will be interpreted as regular middleware and will fail to handle errors.

In my case, I had enabled ES-Lint and it warned me about unused next so I removed it... Later on in the production logs started seeing this error. so do not forget to add this to lint ignore list.

// eslint-disable-next-line no-unused-vars
app.use((err, req, res, next) => {
})
Gwenn answered 2/1 at 3:51 Comment(0)
S
0

If you are using the async/await method:

const notifications = await notifications.aggregate({...})
if(notifications){
  return res.status(200).json({ data: notifications })
}else{
  return res.status(404).json({ message: 'No notifications found'})
}

Make sure that you are including your return statements. Not including a return statement will cause this. Something else that I was doing is I had JSON instead of json, which will most definitely throw an error.

Savil answered 30/12, 2022 at 17:56 Comment(0)
S
0

I had the same issue. I resolved it by change the order of functions (req,next,res) to (req,res,next). May it needs them in a strict order to call them properly!

Sammysamoan answered 7/6, 2023 at 14:53 Comment(0)
C
0

Here's the thing:

the order of (req,res,next) really matters.

In my case the problem was just the order. For example if I want to get user info:

export const getUserInfo = async(res:Response,req:Request,next:NextFunction) => {
try {
    const userId = await req.user 
    const user = await userModel.findById(userId);

res.status(200).json({
    success: true,
    user,
})


} catch (error:any) {
    return next(new ErrorHandler(error.message,400))
}

here I used:

  1. req first
  2. Then I used res

Which was the problem. after switching them on function parameters everything works fine.

Cuspid answered 27/3 at 20:0 Comment(0)
F
-1

I was setting the type of req and res to Request and Response, respectively, without actually importing these types from Express!

Fahey answered 29/6, 2023 at 8:24 Comment(0)
R
-2

Order of parameters really matters i had error in below code

const getImagesByBrand = async (res) => {
  try {
    const images = await Image.find();
    res.status(200).json(images);
  } catch (error) {
    res.status(500).json(error);
  }
};

I was not giving req as parameter and that was the reason for error i just add req,res and it worked

Revert answered 16/8, 2022 at 3:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.