Skip to content

fix(auth): preserve 5xx error message - #2587

Merged
mandarini merged 3 commits into
supabase:masterfrom
7ttp:fix/auth-handle-error-preserve-5xx-body
Aug 3, 2026
Merged

fix(auth): preserve 5xx error message#2587
mandarini merged 3 commits into
supabase:masterfrom
7ttp:fix/auth-handle-error-preserve-5xx-body

Conversation

@7ttp

@7ttp 7ttp commented Jul 31, 2026

Copy link
Copy Markdown
Member

TL;DR:

handleError threw retryable 5xx errors before reading the response body, so every server error surfaced as message: "{}".

Parse the body first, keep the NETWORK_ERROR_CODES classification
a 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:

@7ttp
7ttp requested review from a team as code owners July 31, 2026 18:43
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5de4d749-07f3-48da-a53c-ae008eaf32f6

📥 Commits

Reviewing files that changed from the base of the PR and between d5173a3 and 45e4e2a.

📒 Files selected for processing (2)
  • packages/core/auth-js/src/lib/fetch.ts
  • packages/core/auth-js/test/fetch.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/auth-js/src/lib/fetch.ts
  • packages/core/auth-js/test/fetch.test.ts

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of server and network errors.
    • Retryable errors now preserve meaningful messages returned in valid JSON responses.
    • Non-JSON server errors continue to display their HTTP status appropriately.
    • Network failures now provide clearer fallback messages using available status information when a response cannot be parsed.

Walkthrough

handleError now parses fetch response bodies before classifying network error statuses. JSON 5xx responses provide their parsed server message to AuthRetryableFetchError. Unparseable 5xx responses remain retryable and use status text or an HTTP status fallback. Other parsing failures continue to produce AuthUnknownError. Tests cover JSON 500 responses and non-JSON 502 responses.

Assessment against linked issues

Objective Addressed Explanation
Preserve server-provided messages for retryable 5xx responses [#2585]
Keep non-JSON 5xx responses classified as retryable [#2585]

Suggested labels: auth-js


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 31, 2026

Copy link
Copy Markdown

Open in StackBlitz

@supabase/auth-js

npm i https://pkg.pr.new/@supabase/auth-js@2587

@supabase/functions-js

npm i https://pkg.pr.new/@supabase/functions-js@2587

@supabase/postgrest-js

npm i https://pkg.pr.new/@supabase/postgrest-js@2587

@supabase/realtime-js

npm i https://pkg.pr.new/@supabase/realtime-js@2587

@supabase/storage-js

npm i https://pkg.pr.new/@supabase/storage-js@2587

@supabase/supabase-js

npm i https://pkg.pr.new/@supabase/supabase-js@2587

commit: 0986666

@coveralls

coveralls commented Jul 31, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 73.518% (-7.9%) from 81.419% — 7ttp:fix/auth-handle-error-preserve-5xx-body into supabase:master

@mandarini mandarini left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a clean fix, thanks!! :D Two small things before I merge:

  1. In the catch branch you still pass the Response to _getErrorMessage, so a body-less 5xx keeps reporting "{}". Since that is the whole complaint in the issue, could we use error.statusText || \HTTP ${error.status}`there? The fallback matters because HTTP/2 has no reason phrase, sostatusText` is often an empty string behind the edge.

  2. Both tests use the msg body shape, which is the pre-2024-01-01 format. The client sends the 2024-01-01 API version header by default, and against that the server replies with {"code": "unexpected_failure", "message": "..."} instead. Your fix handles both, since _getErrorMessage checks msg and message, 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 the handleError table you could mirror.

@7ttp
7ttp requested a review from mandarini August 3, 2026 08:16
@mandarini
mandarini merged commit a6bcd6a into supabase:master Aug 3, 2026
30 of 31 checks passed
spydon added a commit to supabase/supabase-flutter that referenced this pull request Aug 10, 2026
## 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 -->
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>
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.

auth-js: handleError discards the response body for 5xx, so every server error reports message: "{}" (regression in 2.108.2)

3 participants