#1654·OpenWA

[Bug]: Pairing-code retry exhaustion and page errors answer 500 instead of 503

Author: rmyndharisCreated Sep 18, 2026Updated Sep 18, 2026

POST /api/sessions/{sessionId}/pairing-code on the whatsapp-web.js engine answers HTTP 500 when its retry budget is exhausted, and when the in-page call throws. Both are conditions a caller can retry, and the repository already has the error class that says so.

Steps to reproduce

  1. Start a whatsapp-web.js session and wait for qr_ready.
  2. POST /api/sessions/{sessionId}/pairing-code while WhatsApp Web is cycling its QR page.
  3. Observe the response when every attempt lands mid-navigation, and when WhatsApp Web raises an error inside the evaluated function.

Expected

A 503 for an exhausted transport retry budget, which is the contract EngineTransportError already carries, and a documented status for an engine-side rejection. A 500 tells a client the gateway is broken and that retrying is pointless.

Actual

Both paths answer 500 with a raw message. The observed shapes are requestPairingCode attempt timed out and a minified WhatsApp Web exception whose message is literally t: t. docs/06-api-specification.md:801 documents 400, 401, 403, 404 and 409 for this route and no 5xx at all, so neither response matches the published contract.

Root cause

  • src/engine/adapters/wwebjs-lifecycle.ts:60-66 defines PairingCodeAttemptTimeoutError extends Error, a plain Error.
  • src/engine/adapters/wwebjs-lifecycle.ts:1077-1078 ends the retry loop with throw lastError, so that plain Error reaches the client.
  • src/engine/adapters/wwebjs-lifecycle.ts:1058-1060 rethrows any non-navigation error raw on the first attempt.
  • No global exception filter or interceptor is registered, so Nest's built-in handler turns any non-HttpException into a 500. Every other engine error maps by subclassing: EngineNotReadyError to 409 (src/common/errors/engine-not-ready.error.ts:13), EngineNotSupportedError to 501 (src/common/errors/engine-not-supported.error.ts:12), EngineTransportError to 503 (src/common/errors/engine-transport.error.ts:14).
  • src/engine/adapters/wwebjs-pairing-code.spec.ts:55-70 pins the plain Error as the expected outcome, so the gap is currently locked in by a test.

The retry loop itself came from #1543, whose suggested fix ended the loop with EngineTransportError; the shipped code ends it with throw lastError.

Suggested direction

End the retry loop with EngineTransportError, keeping the last error's message as the detail so the diagnostic is not lost. Decide separately whether a non-navigation engine rejection should keep propagating raw or be wrapped; if it keeps propagating, document the status the route answers for it. Update the spec and the route's documented error list, which means a new @ApiResponse and a regenerated OpenAPI snapshot.

Environment

  • OpenWA 0.23.4 and a build of main at 62dbe393
  • Engine: whatsapp-web.js 1.34.7