diff --git a/docs/refactor/web-provider-split.md b/docs/refactor/web-provider-split.md index 910721179..cd01be284 100644 --- a/docs/refactor/web-provider-split.md +++ b/docs/refactor/web-provider-split.md @@ -11,6 +11,7 @@ Context: `src/provider-web.ts` was a 900+ line ball of mud mixing session manage - Bounded reconnects: web relay uses capped exponential backoff (default 2s→30s, max 12 attempts). CLI knobs `--web-retries`, `--web-retry-initial`, `--web-retry-max`, `--web-heartbeat` and config `web.reconnect`/`web.heartbeatSeconds` tune the behavior. - Backoff reset after healthy uptime; logged-out state still exits immediately. - Extracted reconnect/heartbeat helpers to `src/web/reconnect.ts` with unit tests. +- Added troubleshooting guide at `docs/refactor/web-relay-troubleshooting.md` (common errors, knobs, logs). ## How to use - Link: `warelay login --provider web` diff --git a/docs/refactor/web-relay-troubleshooting.md b/docs/refactor/web-relay-troubleshooting.md new file mode 100644 index 000000000..0274b82a3 --- /dev/null +++ b/docs/refactor/web-relay-troubleshooting.md @@ -0,0 +1,31 @@ +# Web Relay Troubleshooting (Nov 26, 2025) + +## Symptoms & quick fixes +- **Stream Errored / Conflict / status 409–515:** WhatsApp closed the socket because another session is active or creds went stale. Run `warelay logout` then `warelay login --provider web` and restart the relay. +- **Logged out:** Console prints “session logged out”; re-link with `warelay login --provider web`. +- **Repeated retries then exit:** Reconnects are capped (default 12 attempts). Tune with `--web-retries`, `--web-retry-initial`, `--web-retry-max`, or config `web.reconnect`. +- **No inbound messages:** Ensure the QR-linked account is online in WhatsApp, and check logs for `web-heartbeat` to confirm auth age/connection. + +## Helpful commands +- Start relay web-only: `pnpm warelay relay --provider web --verbose` +- Show who is linked: `pnpm warelay relay --provider web --verbose` (first line prints the linked E.164) +- Logout (clear creds): `pnpm warelay logout` +- Relink: `pnpm warelay login --provider web` +- Tail logs (default): `tail -f /tmp/warelay/warelay.log` + +## Reading the logs +- `web-reconnect`: close reasons, retry/backoff, max-attempt exit. +- `web-heartbeat`: connectionId, messagesHandled, authAgeMs, uptimeMs (every 60s by default). +- `web-auto-reply`: inbound/outbound message records with correlation IDs. + +## When to tweak knobs +- High churn networks: increase `web.reconnect.maxAttempts` or `--web-retries`. +- Slow links: raise `--web-retry-max` to give more headroom before bailing. +- Chatty monitors: increase `--web-heartbeat` interval if log volume is high. + +## If it keeps failing +1) `warelay logout` → `warelay login --provider web` (fresh QR link). +2) Ensure no other device/browser is using the same WA Web session. +3) Check WhatsApp mobile app is online and not in low-power mode. +4) If status is 515, let the client restart once after pairing (already handled automatically). +5) Capture the last `web-reconnect` entry and the status code before escalating. diff --git a/src/web/auto-reply.ts b/src/web/auto-reply.ts index 5629b6707..2b7490fbd 100644 --- a/src/web/auto-reply.ts +++ b/src/web/auto-reply.ts @@ -40,6 +40,7 @@ export async function monitorWebProvider( const runId = newConnectionId(); const replyLogger = getChildLogger({ module: "web-auto-reply", runId }); const heartbeatLogger = getChildLogger({ module: "web-heartbeat", runId }); + const reconnectLogger = getChildLogger({ module: "web-reconnect", runId }); const cfg = loadConfig(); const configuredMaxMb = cfg.inbound?.reply?.mediaMaxMb; const maxMediaBytes = @@ -319,6 +320,16 @@ export async function monitorWebProvider( "isLoggedOut" in reason && (reason as { isLoggedOut?: boolean }).isLoggedOut; + reconnectLogger.info( + { + connectionId, + status, + loggedOut, + reconnectAttempts, + }, + "web reconnect: connection closed", + ); + if (loggedOut) { runtime.error( danger( @@ -334,6 +345,15 @@ export async function monitorWebProvider( reconnectPolicy.maxAttempts > 0 && reconnectAttempts >= reconnectPolicy.maxAttempts ) { + reconnectLogger.warn( + { + connectionId, + status, + reconnectAttempts, + maxAttempts: reconnectPolicy.maxAttempts, + }, + "web reconnect: max attempts reached", + ); runtime.error( danger( `WhatsApp Web connection closed (status ${status}). Reached max retries (${reconnectPolicy.maxAttempts}); exiting so you can relink.`, @@ -344,6 +364,16 @@ export async function monitorWebProvider( } const delay = computeBackoff(reconnectPolicy, reconnectAttempts); + reconnectLogger.info( + { + connectionId, + status, + reconnectAttempts, + maxAttempts: reconnectPolicy.maxAttempts || "unlimited", + delayMs: delay, + }, + "web reconnect: scheduling retry", + ); runtime.error( danger( `WhatsApp Web connection closed (status ${status}). Retry ${reconnectAttempts}/${reconnectPolicy.maxAttempts || "∞"} in ${formatDuration(delay)}…`,