fix(auth): preserve 5xx error message - #2587
Conversation
|
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)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughSummary by CodeRabbit
Walkthrough
Assessment against linked issues
Suggested labels: 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: |
mandarini
left a comment
There was a problem hiding this comment.
This is a clean fix, thanks!! :D Two small things before I merge:
-
In the
catchbranch you still pass theResponseto_getErrorMessage, so a body-less 5xx keeps reporting"{}". Since that is the whole complaint in the issue, could we useerror.statusText || \HTTP ${error.status}`there? The fallback matters because HTTP/2 has no reason phrase, sostatusText` is often an empty string behind the edge. -
Both tests use the
msgbody shape, which is the pre-2024-01-01format. The client sends the2024-01-01API version header by default, and against that the server replies with{"code": "unexpected_failure", "message": "..."}instead. Your fix handles both, since_getErrorMessagechecksmsgandmessage, but it would be good to cover the shape that actually ships. There is already a'with API version 2024-01-01 and error code'entry in thehandleErrortable you could mirror.
## What
`GotrueFetch._handleError` short-circuited on `statusCode >= 500` before
it looked at the body, and set `message: response.body` unconditionally.
That meant:
- a JSON error body such as `{"code":"unexpected_failure","msg":"Error
sending confirmation email"}` surfaced as the raw JSON string instead of
the server sent message
- an HTML error page from a proxy surfaced as a wall of markup
- an empty body surfaced as an empty message
The 5xx check now runs after the body is parsed, so the server sent
message wins. When the body isn't JSON (or is empty), the message falls
back to the response's reason phrase, and then to a synthesized `HTTP
<status>` since HTTP/2 responses carry no reason phrase.
Non-5xx handling is untouched: a non-JSON 4xx body still throws
`AuthUnknownException`.
| Response | Before | After |
| --- | --- | --- |
| 500 with `{"msg":"Error sending confirmation email"}` | `{"msg":"Error
sending confirmation email"}` | `Error sending confirmation email` |
| 502 with an HTML body, reason phrase `Bad Gateway` | the full HTML |
`Bad Gateway` |
| 502 with an HTML body, no reason phrase | the full HTML | `HTTP 502` |
| 503 with an empty body | `` | `Service Unavailable` |
`AuthRetryableFetchException` and its `statusCode` are unchanged, so
retry behavior is unaffected.
## Why
Parity with `supabase-js`, which made the same reordering in
supabase/supabase-js#2587 (`a6bcd6ae`).
Fixes #1651
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Improved authentication error handling for server-side failures.
- Retryable server errors now consistently provide a meaningful message
and status code.
- Error messages now use available server details, HTTP reason phrases,
or a clear status-based fallback.
- Improved handling of empty and malformed error responses.
- Non-JSON client errors are now reported with the appropriate
unknown-error classification.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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>
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>
TL;DR:
handleErrorthrew retryable 5xx errors before reading the response body, so every server error surfaced asmessage: "{}".Parse the body first, keep the
NETWORK_ERROR_CODESclassificationa 5xx with a JSON body now carries the server's message, a body-less 5xx
(gateway HTML page) throws exactly what it did before.
Error class and status unchanged on every path.
ref: