restify / restify/node-restify
Unable to Execute Asynchronous Code (Both Promises and Callbacks) in Middleware
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 10.7k
- Forks
- 975
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 5
Description
Bug Report
I thoroughly searched the existing issues in the Restify repository to check if this problem had already been reported. However, I could not find any issue that matches the exact behavior I am experiencing. While there are some discussions around bodyParser, none of them address the specific problem where the request connection is prematurely marked as closed when handling POST requests
Restify Version
v5.0.0 (also tested on latest version as well)
Node.js Version
v22.11.0 ( also tested with 16.19.0)
OS
Ubuntu 20.04 (WSL2), Windows 11
Expected behaviour
Middleware should proceed sequentially to the next handler when next() is called.
Actual behaviour
When using restify.plugins.bodyParser(), the request connection state is unexpectedly marked as closed. If a middleware function performs an async operation (e.g., setTimeout, async/await), calling next() after the delay results in a RequestCloseError.
This issue only occurs for POST requests.
Code
`
const restify = require('restify');
const server = restify.createServer({ handleUncaughtExceptions: true });
server.pre(function (req, res, next) {
restify.pre.userAgentConnection();
req.start = Date.now();
req.requestId = req.header('X-Request-Id') || req.getId();
return next();
});
server.use(restify.plugins.acceptParser(server.acceptable));
server.use(restify.plugins.authorizationParser());
server.use(restify.plugins.dateParser());
server.use(restify.plugins.queryParser());
server.use(restify.plugins.bodyParser({ mapParams: false }));
server.on('uncaughtException', function (req, res, route, err) {
res.send(500, { code: 'UNKNOWN', message: 'UNKNOWN' });
});
server.on('after', function (req, res, route, error) {
console.log("server after event :: ", error)
});
process.on('exit', function () {
console.log(`Stopped server `);
});
function connectionStateCheck(req, res, next) {
const connection = req.connection;
req.on('close', () => {
console.log(`Connection closed for ${req.url}`);
});
req.on('end', () => {
console.log(`Connection end for ${req.url}`);
});
connection.on('close', () => {
console.log(`Connection closed for ${req.url}`);
});
connection.on('end', () => {
console.log(`Connection ended for ${req.url}`);
});
next();
}
server.use(connectionStateCheck);
function helperMiddleware() {
return function hh(req, res, next) {
console.log("Middleware started");
setTimeout(() => {
console.log("Async operation completed, calling next()");
req.authdata = {};
return next();
}, 3000);
console.log("Middleware function execution ends");
}
}
server.get('/', (req, res, next) => {
console.log("Final handler executed");
res.send("Hello, world!");
next();
});
server.use(helperMiddleware());
server.get('/test', (req, res, next) => {
console.log("test handler executed");
res.send("test, world!");
next();
});
server.post('/testpost', (req, res, next) => {
console.log("testpost handler executed :: ", req.body);
res.send("test, world!");
next();
});
server.listen(8080, () => {
console.log("Server listening on port 8080");
});
`
What's Happening
- Everything works fine until the request hits bodyParser.
- bodyParser executes successfully and passes control to the next middleware (helperMiddleware).
- The next middleware (helperMiddleware) runs synchronously until it reaches setTimeout().
- Before setTimeout() executes, Restify marks the request connection as closed.
- Calling next() after the async operation throws RequestCloseError.
- Removing bodyParser or helperMiddleware fixes the issue but i need both the middleware
- Only affects POST requests (GET requests work fine)
Can anyone please help me with the issue?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the POST /testpost case with restify.plugins.bodyParser({ mapParams: false }) and helperMiddleware, then compare it with the working GET case. Trace the bodyParser-to-middleware request lifecycle and RequestCloseError, and add or update a regression test for delayed next(). Done means asynchronous middleware can call next() after the delay and the POST handler completes without the error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100