Skip to content

[Bug]: 'channels login --channel whatsapp' QR last row malforms due to excessive ANSI escapes (qrcode small=true mode) #77820

@KrasimirKralev

Description

@KrasimirKralev

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

renderQrTerminal(qr, { small: true }) in the WhatsApp channel-login flow produces a final QR-pattern row with ~10× the ANSI-escape-code density of every other row, which can break QR scanning on terminals with strict ANSI parsers, narrow buffers, or limited Unicode font support.

Steps to reproduce

Reproduce using the bundled qrcode library directly, with the same options the WhatsApp login uses (per extensions/whatsapp/src/login.ts:25src/media/qr-terminal.ts):

cd <openclaw source clone>
pnpm install   # if not already
node -e "const qr = require('qrcode'); qr.toString('https://wa.me/login/2@SAMPLE-TOKEN-1234567890ABCDEF', {type:'terminal', small:true}).then(s => process.stdout.write(s))"

Inspect the last printed line versus any other row.

Expected behavior

Each row uses approximately one set of color escape codes per row. Non-final rows in the same output demonstrate this:

[47m[30m ▄▄▄▄▄▄▄ ▄ ▄    ▄▄▄▄▄ ▄▄ ▄ ▄▄▄▄▄▄▄ [0m

(one open-color sequence, content, one reset).

Actual behavior

The last row has color codes wrapped around every individual cell instead of once per row:

[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀ ... [47m[30m[0m

Reproduced on bundled qrcode 1.5.4 (latest as of 2026-05-04, npm view qrcode version). With a 25-cell-wide test QR the last row is 554 characters of mostly ANSI noise vs. ~50 chars per typical row. Bug is consistent across two different input lengths I tested.

OpenClaw version

2026.5.2 (HEAD on main, commit 5b6e552b51)

Operating system

Cross-platform — the bug is in the JS rendering of the QR string itself, not in any specific terminal. Originally noticed on Windows / Git Bash (mintty); reproduces equally in pure Linux node REPLs.

Install method

source clone (git clone openclaw/openclaw && pnpm install)

Model

NOT_ENOUGH_INFO (not model-related)

Provider / routing chain

NOT_ENOUGH_INFO

Additional provider/model setup details

NOT_ENOUGH_INFO

Logs, screenshots, and evidence

Side-by-side from the same QR rendering (raw output of the reproduction command):

Typical row (~50 chars):

[47m[30m ▄▄▄▄▄▄▄ ▄ ▄    ▄▄▄▄▄ ▄▄ ▄ ▄▄▄▄▄▄▄ [0m

Last row (~554 chars):

[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m[37m▀[47m[30m[0m

Impact and severity

Severity: Medium — silent or near-silent failure mode that breaks scannability rather than crashing. Affects users on:

  • WSL default font configurations (already documented as "MS Gothic font workaround" in open PR docs: Add a note regarding the unreadable QR code caused by font limi… #72762; this issue describes the underlying cause).
  • SSH clients with conservative ANSI handling that drop or buffer dense escape sequences.
  • Strict JSON/log parsers ingesting CLI output downstream.
  • Some narrower terminals with per-line buffer limits.

In all of these cases the rest of the QR may render correctly while the last row is missing or malformed, leaving the QR unscannable without obvious error.

Additional information

Hypothesis on the root cause (offered as analysis, not as observed code from upstream):

With small: true, the qrcode library pairs every two QR-pixel rows into one terminal row using ▀ ▄ █ half-block characters. QR matrix dimensions are always odd (21×21, 25×25, 29×29, …), so the last terminal row contains only an upper-QR-pixel row with no lower partner. The library appears to fall into a per-cell color-emission path for this final partial row instead of the per-row-optimized path used for all other rows.

Mitigation options for openclaw (ordered by simplicity):

  • (A) One-liner: change small: opts.small ?? truesmall: opts.small ?? false in src/media/qr-terminal.ts:8. Produces a visually larger QR (full-block chars) but with consistent escape density across all rows, eliminating the broken-last-row mode entirely.
  • (B) Config-gated: add an OPENCLAW_QR_FORMAT=small|large env var so users on terminals that handle the dense escapes fine keep the compact rendering, and users on broken terminals can opt out.
  • (C) Upstream: PR to https://github.com/soldair/node-qrcode fixing the parity bug in the library itself. Right long-term fix but longer cycle.

Related work: open PR #72762 adds WSL-specific font guidance to the CLI — that addresses the user-visible symptom on one platform, while this issue describes the underlying root cause and a more direct fix path.

I'm happy to prepare a PR for option A or B if maintainers indicate the preferred direction. Investigation was AI-assisted; happy to redirect or close if a different approach is preferred.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions