Skip to content

fix(broadcasts): qualify contact_id so create_broadcast_with_recipients can execute (#536) - #537

Closed
neerajgupta2407 wants to merge 1 commit into
ArnasDon:mainfrom
neerajgupta2407:fix/broadcast-contact-id-ambiguity
Closed

neerajgupta2407 wants to merge 1 commit into
ArnasDon:mainfrom
neerajgupta2407:fix/broadcast-contact-id-ambiguity

Conversation

@neerajgupta2407

Copy link
Copy Markdown
Contributor

Fixes #536.

POST /api/v1/broadcasts has never succeeded. create_broadcast_with_recipients is declared RETURNS TABLE(broadcast_id, recipient_id, contact_id), and in PL/pgSQL a RETURNS TABLE output column is also an in-scope variable. The recipient insert ends in a bare RETURNING id, contact_id, so that name resolves against both the target table's column and the function's own output variable, and Postgres aborts:

42702: column reference "contact_id" is ambiguous
       It could refer to either a PL/pgSQL variable or a table column.

The change

One qualified identifier:

-    RETURNING id, contact_id
+    RETURNING id, broadcast_recipients.contact_id

Qualifying it names the column and nothing else. Signature, arguments and result columns are unchanged from 038, so lib/whatsapp/broadcast-core.ts needs no edit — this is a migration-only PR.

The other identifiers in the body are already unambiguous: broadcast_id appears only in an INSERT column list (never a variable reference), and the final SELECT reads through ins.

Why a new 040_ file instead of editing 038

Applied migrations are recorded in schema_migrations — that ledger is what made the duplicate-version collision in 034_fix_profiles_update_rls.sql a hard failure (23505). So editing 038 in place would fix only fresh installs: every existing deployment already has 038 recorded and would keep the broken function forever.

040 is a CREATE OR REPLACE of the exact 038 signature, so it is idempotent and safe to re-run. This is the same shape as 034 repairing 017's policy. Happy to switch to an in-place edit of 038 instead if you'd rather — it's your call on how you want existing installs handled.

Verification

Both function bodies — the current 038 one and the fixed one — created side by side in a clean Postgres 16, then called:

>>> BOTH FUNCTIONS CREATED WITHOUT ERROR (this is the trap)

>>> calling upstream 038 body:
ERROR:  column reference "contact_id" is ambiguous
LINE 5:     RETURNING id, contact_id
                          ^
DETAIL:  It could refer to either a PL/pgSQL variable or a table column.
CONTEXT:  PL/pgSQL function broken(uuid[],jsonb[]) line 5 at RETURN QUERY

>>> calling the 040 fix:
             broadcast_id             |             recipient_id             |              contact_id
--------------------------------------+--------------------------------------+--------------------------------------
 c6a2d459-1eb3-48bf-b98a-d44b312e3d34 | 8cb36b24-61cd-46ac-b874-7d8933cb4bae | 2586670c-632f-4a4c-b333-5cbfb1a5330e
(1 row)

Also confirmed against a live Supabase project inside a BEGIN … ROLLBACK: the function creates the campaign and returns its recipient row, nothing persisted.

Two things worth a follow-up (not in this PR)

A plpgsql body is only parsed at CREATE time — name resolution happens on first execution. Applying a migration proves the function exists, not that it can run, so a check that applies migrations without calling the RPCs they define will go green on a function that is dead on arrival. That is exactly what happened here. A smoke test that invokes each RPC once would have caught this the day 037 landed.

The blast radius hid it. broadcast-core.ts is the only caller, reached from the public API. The dashboard's own broadcast route (POST /api/whatsapp/broadcast) loops sendTemplateMessage and never writes a campaign row, so the UI looks healthy while broadcasts and broadcast_recipients stay empty — which is why this survived from 037 (#370) through 038 (#472) unnoticed.

@neerajgupta2407

Copy link
Copy Markdown
Contributor Author

@ArnasDon Could you Please review this?

@ArnasDon

Copy link
Copy Markdown
Owner

Merged via #566 with your commit and authorship intact — thank you for the precise diagnosis and the one-word fix. The only change was the file number: #533 landed as migration 040 while this was open, so yours ships as 041_fix_broadcast_contact_id_ambiguity.sql. I also took your suggestion about execution-time name resolution and added a CI assertion on pg_get_functiondef so a replay that keeps the 038 body fails the migrations job. Closing this one since the branch can't be renumbered from here.

@ArnasDon ArnasDon closed this Sep 13, 2026
pull Bot pushed a commit to soitun/wacrm that referenced this pull request Sep 13, 2026
Migration 040 was taken by ArnasDon#533 (business-scoped user ids) while ArnasDon#537
was open, so the fix ships as 041. The SQL is unchanged from ArnasDon#537 —
one qualified identifier, broadcast_recipients.contact_id, in the
RETURNING clause of create_broadcast_with_recipients.

verify-schema.sql now checks pg_get_functiondef for the qualified
form, so a replay that silently keeps the 038 body fails the
migrations job instead of going green on a function that cannot run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] create_broadcast_with_recipients aborts with 42702 "contact_id is ambiguous" — POST /api/v1/broadcasts has never worked

2 participants