I’m seeing this issue in a lot of my clients’ applications. The NodeError related to setting headers is frequently encountered in Node.js applications built with Wappler. The error occurs in various parts of the application, indicating that headers are being set or responses are being sent multiple times. This issue results in the following error log:
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info]Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at new NodeError (node:internal/errors:405:5)
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at ServerResponse.setHeader (node:_http_outgoing:648:11)
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at ServerResponse.header (/opt/node_app/node_modules/express/lib/response.js:795:10)
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at ServerResponse.json (/opt/node_app/node_modules/express/lib/response.js:276:10)
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at /opt/node_app/lib/server.js:95:33
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at /opt/node_app/node_modules/@sentry-internal/tracing/cjs/node/integrations/express.js:132:12
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at Layer.handle_error (/opt/node_app/node_modules/express/lib/router/layer.js:71:5)
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at trim_prefix (/opt/node_app/node_modules/express/lib/router/index.js:326:13)
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at /opt/node_app/node_modules/express/lib/router/index.js:286:9
2024-07-27T00:58:14Z app[3d8d7435b0d408] ams [info] at Function.process_params (/opt/node_app/node_modules/express/lib/router/index.js:346:12)
Maybe you can adjust server.js @patrick :
Checking res.headersSent before sending a response. Here is the modified server.js file with this safeguard:
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
process.on('uncaughtException', (e) => {
console.error(e);
});
const config = require('./setup/config');
const debug = require('debug')('server-connect:server');
const secure = require('./setup/secure');
const routes = require('./setup/routes');
const sockets = require('./setup/sockets');
const upload = require('./setup/upload');
const cron = require('./setup/cron');
const http = require('http');
const express = require('express');
const endmw = require('express-end');
const cookieParser = require('cookie-parser');
const session = require('./setup/session');
const cors = require('cors');
const app = express();
app.set('trust proxy', true);
app.set('view engine', 'ejs');
app.set('view options', { root: 'views', async: true });
app.disable('x-powered-by');
if (config.compression) {
const compression = require('compression');
app.use(compression());
}
if (config.abortOnDisconnect) {
app.use((req, res, next) => {
req.isDisconnected = false;
req.on('close', () => {
req.isDisconnected = true;
});
next();
});
}
app.use(cors(config.cors));
app.use(express.static('public', config.static));
app.use(express.urlencoded({ extended: true }));
app.use(express.json({
verify: (req, res, buf) => {
req.rawBody = buf.toString();
}
}));
app.use(cookieParser(config.secret));
app.use(session);
app.use(endmw);
upload(app);
secure(app);
routes(app);
const server = http.createServer(app);
const io = sockets(server, session);
global.io = io;
module.exports = {
server, app, io,
start: function(port) {
app.use((req, res) => {
if (req.accepts('html') && req.url != '/404' && app.get('has404')) {
req.url = '/404';
app.handle(req, res);
} else {
if (!res.headersSent) {
res.status(404).json({
status: '404',
message: `${req.url} not found.`
});
} else {
console.error(`Headers already sent for 404: ${req.url}`);
}
}
});
app.use((err, req, res, next) => {
debug(`Got error? %O`, err);
if (req.accepts('html') && req.url != '/500' && app.get('has500')) {
req.url = '/500';
app.handle(req, res);
} else {
if (!res.headersSent) {
res.status(500).json({
status: '500',
code: config.debug ? err.code : undefined,
message: config.debug ? err.message || err : 'A server error occurred, to see the error enable the DEBUG flag.',
stack: config.debug ? err.stack : undefined,
});
} else {
console.error(`Headers already sent for 500: ${req.url}`);
}
}
});
cron.start();
server.listen(port || config.port, () => {
console.log(`App listening at http://localhost:${config.port}`);
});
}
};