UPDATE/DELETE with both an or=filter and a RETURNINGselect raises 42703 "column does not exist" for the filtered column #47332
Replies: 2 comments
-
|
I investigated this against the current Supabase/PostgREST stack, and this appears to already be fixed in newer PostgREST versions. The issue reproduces on older PostgREST versions where or=(...)
select=...
Prefer: return=representationcan fail with: {
"code": "42703",
"message": "column <table>.<column> does not exist"
}The likely root cause was in the mutation SQL generation path for representation-returning writes. When PostgREST builds an I verified the behavior locally with a minimal repro table: CREATE TABLE IF NOT EXISTS public.test_bug_42703 (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
col1 text,
col2 text,
val integer
);
TRUNCATE TABLE public.test_bug_42703;
INSERT INTO public.test_bug_42703 (col1, col2, val)
VALUES
('a', null, 1),
(null, 'b', 2);Then tested the failing shape: curl -i -X PATCH "http://127.0.0.1:54321/rest/v1/test_bug_42703?or=(col1.not.is.null,col2.not.is.null)&select=id" \
-H "apikey: <anon-key>" \
-H "Authorization: Bearer <anon-key>" \
-H "Content-Type: application/json" \
-H "Prefer: return=representation" \
-d '{"val": 20}'On the current local Supabase stack, this returns The relevant fix appears to be included in PostgREST postgrest/postgrest:v14.12which is already patched. The current local CLI stack I tested is running PostgREST So the resolution should be to ensure the affected hosted/self-hosted environment is running PostgREST Suggested regression coverage:
Given the verification above, I don’t think this needs a Supabase-side code change if the deployed PostgREST version is already |
Beta Was this translation helpful? Give feedback.
-
|
Nice isolation work — "either feature alone is fine, only the combination breaks" is a strong signal this is a genuine PostgREST bug rather than a grants/schema issue, and your What's happening under the hood: on a mutation with Workarounds until it's fixed upstream:
Since this is reproducible and well-scoped, it's worth filing on the PostgREST repo (PostgREST/postgrest) with your minimal curl repro — it'll get triaged faster there than in Discussions. If you can include the PostgREST version (Dashboard → Project Settings → Infrastructure, or the |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Bug report
Describe the bug
PostgREST returns
42703 column "<table>.<column>" does not existfor a column that does exist, on anUPDATE/DELETEthat combines two features on the same request:or=(...)filter, andselect=/Prefer: return=representation).Either feature alone works. Only the combination fails. The column is fully present in Postgres (
information_schemaconfirms it onpublic.user_companies, a single BASE TABLE) and is readable, writable, and grant-complete for the request role.This breaks
@supabase/supabase-jsfor the common.update(...).or(...).select(...)pattern, which emits exactly that combination.To Reproduce
public.user_companieshas columnscheck_employee_id,check_contractor_id,pay_schedule_id. Roleservice_rolehas SELECT/INSERT/UPDATE on all (verified viainformation_schema.role_column_grants).orparens/commas are URL-encoded; a never-matchingidguard keeps every write a no-op, so each probe returns[](or204) when correct, isolating the error.Write, no
or, noselect→ OKWrite, no
or, WITHselect→ OKWrite, WITH
or, noselect→ OKWrite, WITH
orANDselect→ FAILSummary of the 2×2:
A pure read with the same
or=filter (GET ...?select=id&or=(...)) also succeeds — the failure is specific to a mutation that has bothorand a RETURNING projection.The equivalent in
supabase-jsfails the same way, because.update(...).or(...).select(...)emits both:Expected behavior
An
UPDATE/DELETEcombining anor=filter with a RETURNINGselectshould resolve columns identically to either feature used alone. A column resolvable in steps 2 and 3 must remain resolvable in step 4.Screenshots
N/A —
curloutput is inline above.System information
Additional context
Suspected cause. The qualified error (
"user_companies.check_employee_id does not exist") on a table that otherwise resolves suggests the generated mutation SQL aliases the target relation for the RETURNING/CTE wrapper but emits theor-group predicate qualified by the original table name (user_companies.<col>) rather than the alias — making the reference a dangling correlation name, which Postgres reports as 42703 rather than a privilege or cache error. (Hypothesis — generated SQL not directly observable.)Ruled out:
Content-Profile: publicheader was the trigger was an uncontrolled comparison. Withor+selectheld constant, the header makes no difference.pay_schedule_id) resolves fine on this table (noPGRST204on the payload), so the cache is current.NOTIFY pgrst, 'reload schema'and aCOMMENT ON TABLEDDL-triggered reload did not change the behavior.service_rolehas SELECT/INSERT/UPDATE on every column referenced (information_schema.role_column_grants).service_roleJWT and the newsb_secret_key (both map toservice_role).Workaround. Split the mutation so
orandselectnever share a request: read matching ids with theorfilter, then update byid=in.(...).Beta Was this translation helpful? Give feedback.
All reactions