Version
1.3.1
Describe the bug
When using adapter.process(req, res, logic) and the end() closure is called with isInvokeResponseOrExpectReplies=true, it calls res.setHeader() after the bot logic completes:

If the logic callback ends the response early (e.g., res.status(200).end() to flush a 200 before a long-running operation and avoid channel timeouts), the subsequent res.setHeader() call in end() throws:
Error: Cannot set headers after they are sent to the client
This was not an issue with the BotBuilder SDK, which did not call setHeader in the equivalent code path.
To Reproduce
- Call adapter.process(req, res, logic)
- Inside logic, call res.status(200).end() to send the response early
- The adapter's end() closure runs after logic completes and throws the error.
Expected behavior
adapter.process() should not throw if the response has already been sent by user code within the logic callback.
Suggested Fix
Add a res.headersSent guard in the end() closure:
const end = (status: StatusCodes, body?: unknown, isInvokeResponseOrExpectReplies: boolean = false) => {
if (res.headersSent) {
return
}
res.status(status)
if (isInvokeResponseOrExpectReplies) {
res.setHeader('content-type', 'application/json')
}
if (body) {
res.send(body)
}
res.end()
}
Version
1.3.1
Describe the bug

When using adapter.process(req, res, logic) and the end() closure is called with
isInvokeResponseOrExpectReplies=true, it calls res.setHeader() after the bot logic completes:If the logic callback ends the response early (e.g., res.status(200).end() to flush a 200 before a long-running operation and avoid channel timeouts), the subsequent res.setHeader() call in end() throws:
Error: Cannot set headers after they are sent to the clientThis was not an issue with the BotBuilder SDK, which did not call setHeader in the equivalent code path.
To Reproduce
Expected behavior
adapter.process() should not throw if the response has already been sent by user code within the logic callback.
Suggested Fix
Add a res.headersSent guard in the end() closure: