Koa: ctx.throw doesn’t set ctx.status

Created on 30 Aug 2016  Â·  10Comments  Â·  Source: koajs/koa

I stumbled upon this issue when trying to throw an Unauthorized error like:

   ...,
  async (ctx, next) => {
    if (!ctx.state.user) {
      ctx.throw(401, 'Unauthorized');
    }
    ctx.state.payload.user = ctx.state.user;
    return await next();
  }
  ...

The response’ status code always was 404. According to Koa docs the use of ctx.throw above is equivalent to:

   ...,
  async (ctx, next) => {
    if (!ctx.state.user) {
      ctx.status = 401;
      throw new Error('Unauthorized');
    }
    ctx.state.payload.user = ctx.state.user;
    return await next();
  }
  ...

But it isn’t. Setting status first and then throwing an error results in a correct 401 Unauthorized response as expected while using ctx.throw doesn’t.

Looking at the relevant code there is just an http-error created and thrown but nothing indicates that ctx.status is being set.

  throw() {
    throw createError.apply(null, arguments);
  },

So it seems the response comes with status overridden by Koa’s default 404, no matter what status code you pass to ctx.throw.

Most helpful comment

try return ctx.throw(401, 'Unauthorized') ??

All 10 comments

try return ctx.throw(401, 'Unauthorized') ??

Tried already. createError – imported from the third-party http-errors module – is passed the arguments array of context’s .throw method and itself doesn’t care in which order the arguments are passed, as it extracts the values depending on their type.

Found the cause of my problem already. As soon as you catch the error in one of the middleware functions (as I do up the stream), onerror is called with null and doesn’t go ahead with default error handling. So I have to assign the error’s status code to ctx.status myself. My bad! Thanks anyways. Closing.

@oliverwehn mean is we need handle the err in middleware?

@abnerCrack: It means if you want to handle errors (or particular error types) your way instead of relying on Koa’s own basic error handling and responses, you should build middleware taking care of this. Use it up-stream to catch errors down the stream like:

const router = new Router();
router.use(
  function (ctx, next) {
    try {
      // Go down the stream
      return await next();
    } catch (err) {
      // If an error occurs down the stream and no response is sent by
      // another middleware before, the error gets caught up here
      const response = {};
      // Set status on ctx
      ctx.status = parseInt(error.status, 10) || ctx.status || 500;
      // Build response or do whatever you want depending on status 
      switch (ctx.status) {
        case 400:
        case 401:
        case 403:
        case 404:
        case 500: {
          response.error = { message: err.message };
          break;
        }
        default: {
          response.error = { message: 'Unknown error' };
        }
      }
      // End processing by sending response
      ctx.body = response;
    }
  },
  middleware1(),
  middleware2()
);

module.exports = router;

@oliverwehn thanks a lot. I think I met the same problem i will try it

The above code: 403 is duplicated, error is not defined, but thanks for the sample

@reduxdj: Yeah, you’re right. Fixed the code sample. Thanks.

@oliverwehn do you mean that when we want to throw an error, we should both set the ctx.status to 422 and then ctx.throw(422)? That's how it worked for me but I dont feel good on this behaviour:

    async function validate_signup_request(ctx: Koa.Context, next: Function) {
        var result = validate(ctx.request.body);
        if(!result){
            ctx.status=422;
            ctx.throw(422, "Invalid signup request");
        }
        else{
            await next();
        }
    }

If I dont set the ctx.status to 422, the error handler catches the error but the ctx.state is somehow 404

Good to know, thanks.

The problem remains. Thank you for your code example

Was this page helpful?
0 / 5 - 0 ratings

Related issues

usernameisalreadytaken2014 picture usernameisalreadytaken2014  Â·  4Comments

sibelius picture sibelius  Â·  3Comments

tvq picture tvq  Â·  4Comments

edahlseng picture edahlseng  Â·  3Comments

SteveCruise picture SteveCruise  Â·  3Comments