fix(postgrest): honour throwOnError when maybeSingle finds multiple rows - #2580
Merged
mandarini merged 1 commit intoJul 31, 2026
Merged
Conversation
The client-side cardinality check added for postgrest-js#361 synthesises the PGRST116 error itself, but that branch never consulted shouldThrowOnError. Every other error path in processResponse does, and then() has no post-hoc throw, so .maybeSingle().throwOnError() resolved with an error object instead of rejecting. Callers that destructure only data because they trust throwOnError() to raise silently received data === null on duplicate rows. Add the missing check plus offline tests covering all four maybeSingle cardinality outcomes.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughSummary by CodeRabbit
Walkthrough
Assessment against linked issues
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
@supabase/auth-js
@supabase/functions-js
@supabase/postgrest-js
@supabase/realtime-js
@supabase/storage-js
@supabase/supabase-js
commit: |
This was referenced Aug 5, 2026
This was referenced Aug 11, 2026
mandarini
pushed a commit
to supabase/ssr
that referenced
this pull request
Aug 11, 2026
This PR updates `@supabase/supabase-js` to v2.112.3. **Source**: manual --- ## Release Notes ## v2.112.3 ## 2.112.3 (2026-08-11) ### 🩹 Fixes - **supabase:** add trace context headers to canonical CORS allow-list ([#2603](supabase/supabase-js#2603)) - **supabase:** improve trace propagation sampling and diagnostics ([#2604](supabase/supabase-js#2604)) ### ❤️ Thank You - Katerina Skroumpelou @mandarini ## v2.112.2 ## 2.112.2 (2026-08-06) ### 🩹 Fixes - **realtime:** prevent duplicate on bindings ([#2594](supabase/supabase-js#2594)) - **realtime:** clear stale join payload on sign-out ([#2597](supabase/supabase-js#2597)) ### ❤️ Thank You - Filipe Cabaço @filipecabaco - Vaibhav @7ttp ## v2.112.1 ## 2.112.1 (2026-08-05) ### 🩹 Fixes - **auth:** preserve 5xx error message ([#2587](supabase/supabase-js#2587)) - **realtime:** ensure setAuth doesn't disable token refresh ([#2592](supabase/supabase-js#2592)) ### ❤️ Thank You - Eduardo Gurgel - Vaibhav @7ttp ## v2.112.0 ## 2.112.0 (2026-08-03) ### 🚀 Features - **supabase:** move OpenTelemetry tracing to opt-in /tracing subpath ([#2583](supabase/supabase-js#2583)) ### 🩹 Fixes - **auth:** accept uppercase UUIDs in validateUUID ([#2467](supabase/supabase-js#2467)) - **postgrest:** honour throwOnError when maybeSingle finds multiple rows ([#2580](supabase/supabase-js#2580)) - **storage:** resolve createSignedUrls return type mismatch ([#2474](supabase/supabase-js#2474)) - **storage:** expose service error code on StorageApiError ([#2537](supabase/supabase-js#2537)) - **supabase:** forward db retry option ([#2571](supabase/supabase-js#2571)) ### ❤️ Thank You - Anubhav Anand @i-anubhav-anand - Gourab Singha @gourabsingha1 - Juhef @juheff - Katerina Skroumpelou @mandarini - Thribhuvan - Vaibhav @7ttp - Zuhef Ahmed @Zuhef This PR was created automatically. Co-authored-by: supabase-workflow-trigger[bot] <266661614+supabase-workflow-trigger[bot]@users.noreply.github.com>
mandarini
pushed a commit
to supabase/supabase
that referenced
this pull request
Aug 11, 2026
This PR updates @supabase/*-js libraries to version 2.112.3. **Source**: manual **Changes**: - Updated @supabase/supabase-js to 2.112.3 - Updated @supabase/auth-js to 2.112.3 - Updated @supabase/realtime-js to 2.112.3 - Updated @supabase/postgest-js to 2.112.3 - Refreshed pnpm-lock.yaml --- ## Release Notes ## v2.112.3 ## 2.112.3 (2026-08-11) ### 🩹 Fixes - **supabase:** add trace context headers to canonical CORS allow-list ([#2603](supabase/supabase-js#2603)) - **supabase:** improve trace propagation sampling and diagnostics ([#2604](supabase/supabase-js#2604)) ### ❤️ Thank You - Katerina Skroumpelou @mandarini ## v2.112.2 ## 2.112.2 (2026-08-06) ### 🩹 Fixes - **realtime:** prevent duplicate on bindings ([#2594](supabase/supabase-js#2594)) - **realtime:** clear stale join payload on sign-out ([#2597](supabase/supabase-js#2597)) ### ❤️ Thank You - Filipe Cabaço @filipecabaco - Vaibhav @7ttp ## v2.112.1 ## 2.112.1 (2026-08-05) ### 🩹 Fixes - **auth:** preserve 5xx error message ([#2587](supabase/supabase-js#2587)) - **realtime:** ensure setAuth doesn't disable token refresh ([#2592](supabase/supabase-js#2592)) ### ❤️ Thank You - Eduardo Gurgel - Vaibhav @7ttp ## v2.112.0 ## 2.112.0 (2026-08-03) ### 🚀 Features - **supabase:** move OpenTelemetry tracing to opt-in /tracing subpath ([#2583](supabase/supabase-js#2583)) ### 🩹 Fixes - **auth:** accept uppercase UUIDs in validateUUID ([#2467](supabase/supabase-js#2467)) - **postgrest:** honour throwOnError when maybeSingle finds multiple rows ([#2580](supabase/supabase-js#2580)) - **storage:** resolve createSignedUrls return type mismatch ([#2474](supabase/supabase-js#2474)) - **storage:** expose service error code on StorageApiError ([#2537](supabase/supabase-js#2537)) - **supabase:** forward db retry option ([#2571](supabase/supabase-js#2571)) ### ❤️ Thank You - Anubhav Anand @i-anubhav-anand - Gourab Singha @gourabsingha1 - Juhef @juheff - Katerina Skroumpelou @mandarini - Thribhuvan - Vaibhav @7ttp - Zuhef Ahmed @Zuhef ## v2.111.0 ## 2.111.0 (2026-07-28) ### 🚀 Features - **auth:** store PKCE verifiers in per-flow slots to survive overlapping flows ([#2569](supabase/supabase-js#2569)) ### ❤️ Thank You - Katerina Skroumpelou @mandarini This PR was created automatically. Co-authored-by: supabase-workflow-trigger[bot] <266661614+supabase-workflow-trigger[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What kind of change does this PR introduce?
Bug fix
What is the current behavior?
Fixes #2579
Since the fix for postgrest-js#361,
.maybeSingle()no longer sendsAccept: application/vnd.pgrst.object+json— it fetches a list and enforces cardinality client-side, synthesisingPGRST116when more than one row comes back:That branch never consults
this.shouldThrowOnError. Every other error path inprocessResponsedoes — the non-2xx path ends withif (error && this.shouldThrowOnError) throw new PostgrestError(error)— andthen()has no post-hoc throw, so throwing only ever happens at those sites.The result is that
.maybeSingle().throwOnError()resolves with an error object instead of rejecting, which contradicts whatthrowOnError()documents ("reject the promise by throwing the error instead of returning it as part of a successful response").That fails in the unhelpful direction. Code written as
destructures only
dataprecisely because it truststhrowOnError()to raise. With duplicate rows it quietly getsdata === nulland no exception, so the condition is swallowed rather than surfaced.What is the new behavior?
The synthesised
PGRST116now rejects with aPostgrestErrorwhenthrowOnError()is active, matching what happens when PostgREST itself returns that error.Behaviour without
throwOnError()is unchanged: stillstatus: 406,statusText: 'Not Acceptable',error.code: 'PGRST116',data: null. The returned error object is untouched — includinghint: null, which existing snapshots inbasic.test.tsandtransforms.test.tsassert.PostgrestErrortypeshintasstring, so the throw passeshint: error.hint ?? '', consistent with the other synthesised throw in this file which useshint: ''.Additional context
maybeSingle()+throwOnError()had no test coverage — the existingPGRST116assertions check the returned error object rather than the throwing path, and they need the Dockerised PostgREST. The newtest/maybe-single.test.tsuses a mocked fetch, so it runs offline and pins all four cardinality outcomes: one row, zero rows, multiple rows, and multiple rows withthrowOnError().Verification, from
packages/core/postgrest-js:Before the source change, the new suite is
1 failed, 3 passed, with:Across the suites that run without Docker (
fetch-errors,headers-serialization,retry,max-affected,permission-hints,maybe-single): 45 passed / 6 failed with this change, versus 44 passed / 7 failed on an unmodified checkout — the one flipped test is the new one, and nothing else moved. The 6 remaining failures are all inmax-affected.test.tsand fail withECONNREFUSED; they need the local PostgREST fromdocker compose, which isn't available in my environment, so those are untouched-but-unverified by me.Also checked:
tsc --noEmit --project tsconfig.json— clean.tsc --noEmit --project tsconfig.test.json— clean.prettier --check— clean on both files.