Sujeet
Sujeet

Reputation: 3810

catch error for bad json format thrown by express.json() middleware

I am getting SyntaxError: Unexpected string in JSON at position 59 error in html format when format of json data is not valid. I don't know why it is giving me html instead of error object.
I have set my header like below.


//header middlewares
app.use((req, res, next) => {
    res.setHeader('Content-Type', 'application/json');
    res.setHeader("Access-Control-Allow-Origin", "*");
    next();
  });

I want to catch the error and send a message in below format.

{ 
  "status":404,
  "message":Unexpected string in JSON at position 59
}

Here is the error that I get.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>SyntaxError: Unexpected string in JSON at position 59<br> &nbsp; &nbsp;at JSON.parse (&lt;anonymous&gt;)<br> &nbsp; &nbsp;at parse (C:\Users\mydirectory\auth\node_modules\body-parser\lib\types\json.js: 89: 19)<br> &nbsp; &nbsp;at C:\Users\mydirectory\auth\node_modules\body-parser\lib\read.js: 121: 18<br> &nbsp; &nbsp;at invokeCallback (C:\Users\mydirectory\auth\node_modules\raw-body\index.js: 224: 16)<br> &nbsp; &nbsp;at done (C:\Users\my-directory\auth\node_modules\raw-body\index.js: 213: 7)<br> &nbsp; &nbsp;at IncomingMessage.onEnd (C:\Users\mydirectory\auth\node_modules\raw-body\index.js: 273: 7)<br> &nbsp; &nbsp;at IncomingMessage.emit (events.js: 203: 15)<br> &nbsp; &nbsp;at endReadableNT (_stream_readable.js: 1145: 12)<br> &nbsp; &nbsp;at process._tickCallback (internal/process/next_tick.js: 63: 19)</pre>
</body>
</html>


I tried catching this error.

app.use((err, req, res, next) => {
    if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
        console.error(err);
        return res.status(400).send(err); // Bad request
    }
    next();
});


But the response that I get now is like below.

{
    "expose": true,
    "statusCode": 400,
    "status": 400,
    "body": "{\n\t\"username\":\n}",
    "type": "entity.parse.failed"
}

Upvotes: 22

Views: 15452

Answers (4)

Sujeet
Sujeet

Reputation: 3810

I posted this question on expressjs github repo, and I got a nice and reasonable solution.

If you want that specific response, that is what you need to send in your error handler instead of the err object itself.

 app.use((err, req, res, next) => {
    if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
        console.error(err);
        return res.status(400).send({ status: 400, message: err.message }); // Bad request
    }
    next();
});

Now I am able to send the desired response.

{
   "status": 400,
   "message": "Unexpected string in JSON at position 37"
}

Link to issue

Upvotes: 28

Naor Tedgi
Naor Tedgi

Reputation: 5699

if you want to catch all errors thrown by body-parsr for example entity.too.large or encoding.unsupported

just place this middleware right after your body-parser initialization

$ npm i express-body-parser-error-handler

https://www.npmjs.com/package/express-body-parser-error-handler

for example:

const bodyParserErrorHandler = require('express-body-parser-error-handler')
const { urlencoded, json } = require('body-parser')
const express = require('express')
const app = express();
router.route('/').get(function (req, res) {
    return res.json({message:"🚀"});
});

// body parser initilization
app.use('/', json({limit: '250'}));

// body parser error handler
app.use(bodyParserErrorHandler());
app.use(router);
...

Upvotes: 0

Amadou Beye
Amadou Beye

Reputation: 2808

You will have to handle parsing error separately like below:

app.use((err, req, res, next) => {
    if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
        if (err.type === 'entity.parse.failed') {
            let data = req.body || req.query;
            try {
                JSON.parse(data); // <-- reproduce error in order to catch it
            } catch (error) {
                // get the first line of error which is "SyntaxError: Unexpected string in JSON at position 59"
                let message = error.toString().split("\n")[0];
                return res.status(400).send({ status: 400, message: message }); // Bad request
            }
        }            
        else return res.status(400).send(err); // Bad request
    }
    next();
});

Upvotes: 4

jfarleyx
jfarleyx

Reputation: 785

Try creating an object to store the error details you want and return those as json...

app.use((err, req, res, next) => {
    if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
        let formattedError = {
          status: err.statusCode,
          message: err.message
        }
        return res.status(err.statusCode).json(formattedError); // Bad request
    }
    next();
});

Upvotes: 0

Related Questions