Skip to content

Commit 5b2a2fb

Browse files
committed
fix(msteams): handle invalid JSON escape sequences in Bot Framework activities
Some Bot Framework clients (e.g. certain MS Teams clients) send activity payloads that contain invalid JSON escape sequences such as bare backslashes followed by characters not defined in RFC 8259 (e.g. \p, \q, \c). The previous `express.json()` middleware uses body-parser's strict JSON parser which throws `SyntaxError: Bad escaped character in JSON` on such payloads. This causes the webhook to return a non-200 response, putting Azure Bot Service into exponential backoff and dropping subsequent messages. This fix replaces `express.json()` with `express.raw()` (raw Buffer body), then adds a two-pass JSON parse middleware: 1. First tries standard JSON.parse on the raw body. 2. If that fails (SyntaxError), attempts to repair the payload by double-escaping bare backslashes: /\\([^"\\/bfnrtu])/g → \\\\$1 3. If the repaired payload parses successfully, logs a warning and continues normally so the activity is processed. 4. If the payload cannot be repaired, responds with HTTP 200 to prevent Azure Bot Service backoff, and logs the error for investigation. Fixes: SyntaxError: Bad escaped character in JSON at position N Tested: conversationUpdate and message activities from MS Teams clients
1 parent 88ee571 commit 5b2a2fb

File tree

1 file changed

+39
-2
lines changed

1 file changed

+39
-2
lines changed

extensions/msteams/src/monitor.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,12 +269,49 @@ export async function monitorMSTeamsProvider(
269269

270270
// Create Express server
271271
const expressApp = express.default();
272-
expressApp.use(express.json({ limit: MSTEAMS_WEBHOOK_MAX_BODY_BYTES }));
272+
273+
// Use raw body parser so we can repair invalid JSON escape sequences that some
274+
// Bot Framework clients include in activity payloads (e.g. conversationUpdate
275+
// activities with bare backslashes like \p or \q that are not valid per RFC 8259).
276+
// The strict express.json() parser throws SyntaxError on such payloads, which
277+
// causes a non-200 response and puts Azure Bot Service into exponential backoff,
278+
// dropping all subsequent messages until the backoff window expires.
279+
expressApp.use(express.raw({ type: "application/json", limit: MSTEAMS_WEBHOOK_MAX_BODY_BYTES }));
280+
expressApp.use((req: Request, _res: Response, next: (err?: unknown) => void) => {
281+
if (Buffer.isBuffer(req.body)) {
282+
const rawText = req.body.toString("utf-8");
283+
try {
284+
req.body = JSON.parse(rawText);
285+
} catch {
286+
// Attempt to repair invalid escape sequences by double-escaping bare
287+
// backslashes (e.g. \p → \\p). This recovers payloads sent by certain
288+
// Teams clients that violate the JSON spec.
289+
const fixed = rawText.replace(/\\([^"\\/bfnrtu])/g, "\\\\$1");
290+
try {
291+
req.body = JSON.parse(fixed);
292+
log.warn("msteams: repaired invalid JSON escape sequences in Bot Framework activity");
293+
} catch (parseErr) {
294+
next(parseErr);
295+
return;
296+
}
297+
}
298+
}
299+
next();
300+
});
273301
expressApp.use((err: unknown, _req: Request, res: Response, next: (err?: unknown) => void) => {
274-
if (err && typeof err === "object" && "status" in err && err.status === 413) {
302+
if (err && typeof err === "object" && "status" in err && (err as { status: number }).status === 413) {
275303
res.status(413).json({ error: "Payload too large" });
276304
return;
277305
}
306+
if (err instanceof SyntaxError) {
307+
// JSON could not be repaired; acknowledge with HTTP 200 to prevent Azure
308+
// Bot Service from entering exponential backoff for an unrecoverable payload.
309+
log.error("msteams: unrecoverable JSON parse error in Bot Framework activity", {
310+
error: String(err),
311+
});
312+
res.status(200).end();
313+
return;
314+
}
278315
next(err);
279316
});
280317
expressApp.use(authorizeJWT(authConfig));

0 commit comments

Comments
 (0)