For some time now, we no longer see any stack traces server-side in dev. Attempts to remedy this situation have included:
const server = express();
server.use((err, req, res, next) => {
console.error('err', err);
next(err);
// res.status(500).send('Something broke!');
});
and
const errorHandler = require('errorhandler');
server.use(
errorHandler({
log(err, str, req) {
console.log('log error', err);
console.log('str', str);
// console.log('req', req);
},
})
);
all to no avail.
For example:
server.get('/crash', (req, res, next) => {
boom; // this line crashes
});
calling this endpoint does indeed crash, but no stack trace is visible in the server log.
We launch with:
npm run debug
which is configured like this in package.json:
"scripts": {
"debug": "node --max-old-space-size=4096 --inspect node_modules/nuxt/bin/nuxt",
What are we doing wrong?
Related
const express = require('express')
const app = express();
function middleWear1(req, res, next) {
throw Error()
}
function errorHandler(err, req, res, next) {
console.log("error handled");
res.end("error occured at server")
}
app.use(middleWear1)
app.use(errorHandler)
app.get('/', middleWear1)
app.listen(8000, () => {
console.log("server is listening");
})
when I do localhost:8000 I get "error handled" printed two times in NodeJS terminal.
can some one explain why is it happening?
Assuming you requested localhost:8000 through your web-browser, your browser will not only load http://localhost:8000/ but http://localhost:8000/favicon.ico as well. This is default browser behaviour.
Now, since you've setup middleWear1 to run for every request and the two requests are sent to your server, error handled gets printed twice to the console.
To answer you question from the comment:
In order to prevent middleWear1 running for all requests and only for your / route, you can do:
const express = require('express')
const app = express()
function middleWear1(req, res, next) {
throw Error()
}
function errorHandler(err, req, res, next) {
console.log("error handled");
res.end("error occured at server")
}
app.get('/', middleWear1)
app.use(errorHandler)
app.listen(8000, () => {
console.log("server is listening");
})
Can someone explain to me about the different between two ways exception error handling in code Express JS below:
const express = require('express');
const app = express();
app.get('/test', (req, res, next) => {
// the first way:
throw new Error('my error message');
// the second way:
next(new Error('my error message'));
});
app.use((err, req, res, next) => {
res.status(err.status || 500).send(err.message || 'Internal Server Error');
});
app.listen(3000, () => console.log('Welcome to ExpressJS'));
It returns the same result handled by error middleware but what is the difference here?
Nothing, based on the source code.
try {
fn(req, res, next);
} catch (err) {
next(err);
}
Before uploading my code to Heroku, my API calls worked just fine. However, it returns a status code of 503 (Service Unavailable) after deployment.
This is my code
app.js file in my root folder (server file)
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true }).then(() => console.log("Connected to db!")).catch(dbErr => console.log(dbErr));
app.use(express.json());
app.use(cors());
app.post("/post-result", async (req, res) => {
console.log(req.body.val);
const newSurvey = new survey({ surveyValues: req.body.val });
await newSurvey.save()
.then(data => {
res.send(newSurvey);
console.log(newSurvey);
}).catch(err => console.log(err));
});
app.get("/results", async (req, res) => {
const result = await survey.find({});
res.send(result);
});
if (process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, "/client/build")));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "client", "build", "index.html"));
})
} else {
app.get("/", (req, res) => {
res.send("API running");
})
}
app.listen(process.env.PORT, () => console.log("Listening on PORT 8080"));
My react file, where the API calls were made
const handleFormSubmit = async (e, val) => {
const { data } = await Axios.post("/post-result", { val });
}
package.json file
{
"scripts": {
"start": "nodemon app.js",
"heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client"
},
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"mongoose": "^6.0.12"
}
}
Error log in the console
Uncaught (in promise) Error: Request failed with status code 503 at e.exports createError.js:16) at e.exports (settle.js:17) at XMLHttpRequest.S (xhr.js:66)
Option 1 :
Maybe you should try using all the url instead of Axios.post("/post-result",{..}) You can use local variable to determine if you are in Prod or in local environment, create in util folder a file called for example baseUrl.js :
const baseUrl = process.env.NODE_ENV === "production"
? "https://[your url used in port]"
: "http://localhost:[your port]";
export default baseUrl;
And then import baseUrl in your folder and replace your Axios request by :
const { data } = await Axios.post(baseUrl + "/post-result", { val });
Option 2 :
Also I noticed that you don't allow any URL in Cors Options :
let corsOptions = {
origin: ["URL ALLOWED", ...],
};
app.use(cors(corsOptions));
I have a node.js express app, and i'd like to catch any
<variable> is not defined
or
<object> does not have property <propertyname>
When i run the project locally, and a programmable error occurs I get these messages in the console and the request gets disposed. I want to handle them in the winston logger instead.
Thanks in advance
Removing dependencies from your code and testing with minimum reproducible snippet seem to work for me.
Update
Unhandled rejections can be handled using unhandledRejection
var express = require('express'),
path = require('path');
process.on('uncaughtException', function(err) {
console.log('uncaught exception', err);
}).on('unhandledRejection', (reason, p) => {
console.log('unhandledRejections reason', reason);
}).on('warning', (warning) => {
console.log(`warning, ... ${warning}`);
});
var app = express();
app.use('/api/subscriber', (req, res) => {
console.log('inside API');
return new Promise((resolve, reject)=>{
console.log(undeclaredVariable); // should error
res.status(200).send({
msg: 'hello world'
});
});
});
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
app.use(function (err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
app.listen(process.env.PORT || 5000); // Listen for requests
It logs
inside API
unhandledRejections reason [ReferenceError: undeclaredVariable is not defined]
I'm trying to get error handling running with express but instead of seeing a response of "error!!!" like I expect I see "some exception" on the console and then the process is killed. Is this how error handing is supposed to be setup and if so is there another way to catch errors?
var express = require('express');
var app = express();
app.use(function(err, req, res, next) {
console.log("error!!!");
res.send("error!!!");
});
app.get('/', function(request, response) {
throw "some exception";
response.send('Hello World!');
});
app.listen(5000, function() {
console.log("Listening on 5000");
});
An example app/guide on error handling is available at
https://expressjs.com/en/guide/error-handling.html
However should fix your code:
// Require Dependencies
var express = require('express');
var app = express();
// Middleware
app.use(app.router); // you need this line so the .get etc. routes are run and if an error within, then the error is parsed to the next middleware (your error reporter)
app.use(function(err, req, res, next) {
if(!err) return next(); // you also need this line
console.log("error!!!");
res.send("error!!!");
});
// Routes
app.get('/', function(request, response) {
throw "some exception";
response.send('Hello World!');
});
// Listen
app.listen(5000, function() {
console.log("Listening on 5000");
});
A few tips:
1) Your code wasn't working because your error handler middleware was run before your route was reached, so the error handler never had a chance to have the error passed to it. This style is known as continuation passing. Put your error handler last in the middleware stack.
2) You should shut down the server when you have an unhandled error. The best way to do that is to call server.close(), where server is the result of doing var server = http.createServer(app);
Which means, you should do something like this:
var server = http.createServer(app);
app.use(function(err, req, res, next) {
console.log("error!!!");
res.send("error!!!");
server.close();
});
You should probably also time out the server.close(), in case it can't complete (your app is in an undefined state, after all):
var server = http.createServer(app);
app.use(function(err, req, res, next) {
console.log("error!!!");
res.send("error!!!");
server.close();
setTimeout(function () {
process.exit(1);
}, 3*1000);
});
I made a library that does all this for you, and lets you define custom responses, including specialized error views, static files to serve, etc...:
https://github.com/ericelliott/express-error-handler
I had the same problem and couldn't figure out what was wrong.
The thing is if you have the express errorHandler defined then your custom error handler is never being called.
If you have the next code, simply remove it:
if ('development' === app.get('env')) {
app.use(express.errorHandler());
}
Worked for me:)
Installing express install connect-domain, then something like this:
var express = require("express"),
connectDomain = require("connect-domain"),
app = express(),
errorHandler;
// Our error handler
app.use(connectDomain());
errorHandler = function (err, req, res, next) {
res.send(500, {
"status": "error",
"message": err.message
});
console.log(err);
};
Then when setting up your endpoints, tack errorHandler on the end in a use():
app.get("/some/data", function (req, res) {
// ... do some stuff ...
res.send(200, "Yay! Happy Success!");
}).use(errorHandler);
Create an error function:
function throwError(status, code, message) {
const error = new Error(message);
error.name = '';
error.status = status;
error.code = code;
throw error;
}
e.g.
throwError(422, 'InvalidEmail', '`email` should be a valid email address')
We assign name to '' so that when we toString the error it doesn't prepend it with "Error: "
As mentioned if you're using express you can create a special error handling middleware by specifying 4 arguments:
app.use((err, req, res, next) => {
if (err) {
res.status(err.status || 500).json({ code: err.code || 'Error', message: err.toString() });
}
});
If you're not using express or otherwise prefer, add that code to your catch handler instead.
Why?
Modern apps handle JSON, throwing errors in JSON makes more sense and results in cleaner UI code.
You should not only throw error messages because they are imprecise to parse. What if the UI is a multilingual app? In that case they can use the code to show a localized message.
Found that recipes from here and even in official documentation brake logging for advanced loggers like pino-http (at least for latest express4). Problem appears when you write like this:
app.use((err, req, res, next) => {
if (!err) {
return next();
}
res.status(err.status || 500).json({ error });
});
Express "thinks" that it's normal result and logger does not log error.
{
...
"res":{"status":400},
"msg":"request completed"
}
Fix here (the first line):
res.err = err;
res.status(err.status || 500).json({ error });
Log output after the fix:
{
...
"res":{"status":400},
"msg":"request errored",
"err":{"type":"Error","message":"Some error","stack":"..skip.."}
}