| name | wa-debug |
| description | Diagnose a broken WhatsApp/Uazapi integration on a Supabase stack by isolating which link of the chain failed — messages not arriving, messages not sending, QR not connecting, inbox not updating in realtime, queries returning empty arrays, 401 from the provider, media not loading, or duplicated and re-queued webhook events. Use when WhatsApp worked and stopped, when it never worked, or before changing code to "try something". |
| license | MIT |
| compatibility | Any project running the WhatsApp/Uazapi module on Supabase. Read-only diagnosis by default; needs Supabase CLI or dashboard access to read function logs. |
| metadata | {"version":"1.0.0","part-of":"whatsapp-uazapi"} |
Diagnose a WhatsApp/Uazapi integration
WhatsApp bugs look mysterious and are almost never mysterious. The chain has
seven links, and the failure is at exactly one of them. Isolate the link
first, then read that link's code — changing code before locating the break
is how afternoons disappear.
Reference: ../whatsapp-uazapi/references/, artifacts in
../whatsapp-uazapi/assets/.
The chain
[1] Tenant config whatsapp_configs: endpoint + admintoken
[2] Instance whatsapp_instances: uazapi_token + status = connected
[3] Webhook registered on the instance, pointing to the public function URL
[4] Public function whatsapp-webhook, verify_jwt = false, answers 2xx
[5] Database write upsert conversation + insert message (service role)
[6] Realtime table in supabase_realtime publication
[7] Frontend RLS + GRANT let this user read the rows
Inbound (message not arriving) breaks at 3, 4, 5, 6 or 7.
Outbound (message not sending) breaks at 1, 2 or in phone normalization.
Step 1 — locate the break, do not guess
Ask which symptom, then run only the checks for that branch.
"Messages don't arrive in the inbox"
select id, direction, message_type, left(content, 40) as preview, sent_at
from whatsapp_messages order by sent_at desc limit 10;
-
Rows exist → the break is downstream: [6] Realtime or [7] RLS/GRANT.
select tablename from pg_publication_tables where pubname = 'supabase_realtime';
select count(*) from whatsapp_conversations;
Empty result with no error is the signature of a missing GRANT or a
broken tenancy function — not of missing data.
-
No rows → the break is upstream: [3] or [4].
supabase functions logs whatsapp-webhook --limit 50
- No log entries at all → Uazapi is not calling you. Check that the
webhook is registered on the instance (
configure-uazapi-webhook) and that
the URL is the public function URL, reachable from the internet.
- 401 / 403 in the logs →
verify_jwt is still true for
whatsapp-webhook in config.toml. It is the one function that must be
false.
- Entries with "ignored" / early return → the payload shape did not match
the provider detection. Compare the logged payload with
../whatsapp-uazapi/assets/examples/uazapi-webhook-payloads.md.
- Errors resolving the instance → the event's token/name does not match
any row in
whatsapp_instances. Usually the instance was recreated on the
provider side without updating uazapi_token.
"Messages don't send"
select id, status, uazapi_instance_id, is_active from whatsapp_instances;
status <> 'connected' → the session dropped. Re-pair through the QR flow;
do not debug sending until status is connected.
- 401 from Uazapi → wrong auth header.
admintoken creates instances;
everything else uses the instance token. See
../whatsapp-uazapi/SKILL.md §2.
- 200 from Uazapi but nothing on the phone → phone normalization. This is
the most common outbound bug. Check the exact string sent:
- group JID that lost its
@g.us (a replace(/\D/g, "") ran over it),
- doubled country code (
555511…),
- missing country code.
Rules and test table:
../whatsapp-uazapi/assets/examples/formatacao-telefone.md.
"QR never connects"
- QR renders but scanning does nothing → the QR expired. They are short-lived;
regenerate through
/instance/connect and scan immediately.
- QR does not render → check
create-uazapi-instance logs. A 401 there means
the admintoken is wrong or absent in whatsapp_configs.
- Connects and then drops within minutes → the same WhatsApp account is paired
elsewhere, or the instance was deleted provider-side.
"The inbox doesn't update by itself" (but a refresh shows the message)
Purely link [6]. The row was written; Realtime is not delivering.
select tablename from pg_publication_tables where pubname = 'supabase_realtime';
alter publication supabase_realtime add table whatsapp_messages;
Also confirm the frontend subscription filters match the rows being written
(tenant id, instance id) — a filter that never matches looks exactly like a
Realtime outage.
"Everything returns an empty array, no error"
The signature failure of this stack. In order:
select grantee, privilege_type from information_schema.role_table_grants
where table_name = 'whatsapp_conversations';
select public.get_user_company_ids(auth.uid());
select policyname, qual from pg_policies where tablename = 'whatsapp_conversations';
A policy that queries an RLS-protected table directly (instead of going
through the SECURITY DEFINER function) fails silently — that is the trap the
function exists to avoid.
"Media doesn't load"
Uazapi media URLs expire. The module caches media in the
whatsapp-media-cache bucket via download-whatsapp-media. Check that the
function is deployed, the bucket exists, and cached_media_url is being
written. An expired original URL with no cache is the normal symptom.
"The same message appears several times" / "Uazapi keeps resending"
The webhook answered non-2xx, so the provider re-queued. Every path — including
ignored payloads and handled errors — must return 200. Search the function for
returns with a status other than 200.
Step 2 — report before fixing
State, in three lines: which link broke, the evidence (log line, query
result, exact payload), and the fix. Then ask before changing anything that
deploys or migrates.
Do not report a probable cause as a certainty. If two links are still possible,
say which check separates them.
Step 3 — fixing
- Compare the project's file with the packaged artifact in
../whatsapp-uazapi/assets/ before rewriting anything — the difference is
usually the bug.
- Fix one link at a time and re-run that link's check.
- Never paste tokens, phone numbers or message content into the report.
Things that are not bugs
- Group chats missing from the inbox — by design, unless the instance has
receive_group_messages = true.
unread_count not decrementing — it is cleared by mark-whatsapp-read,
which the UI calls on open; check the call, not the webhook.
- Old conversations with a mangled
phone — rows created before the group
JID fix. sync-whatsapp-chats carries an auto-repair path for them.
- A message sent from the phone itself appearing as outbound — correct:
fromMe events are real and belong in the thread.