Skip to content

fix(postgrest): decode PostgrestError details field - #1159

Open
AndroidPoet wants to merge 4 commits into
supabase:mainfrom
AndroidPoet:fix/postgrest-error-details-decode
Open

fix(postgrest): decode PostgrestError details field#1159
AndroidPoet wants to merge 4 commits into
supabase:mainfrom
AndroidPoet:fix/postgrest-error-details-decode

Conversation

@AndroidPoet

Copy link
Copy Markdown
Contributor

What

PostgrestError.detail is always nil. PostgREST sends the field as details (plural), the Swift property is detail (singular), and there were no CodingKeys to bridge them — so the value has never bound.

This adds the key mapping. The property name is unchanged.

Why it never worked

PostgrestClient.Configuration.jsonDecoder is JSONDecoder.supabase(), which configures only a dateDecodingStrategy — there is no keyDecodingStrategy, so nothing rewrites detailsdetail at decode time.

PostgREST error bodies look like this:

{
  "code": "23505",
  "details": "Key (id)=(1) already exists.",
  "hint": "Use a different id.",
  "message": "duplicate key value violates unique constraint \"users_pkey\""
}

code, hint and message decode fine. Only detail silently drops, so the most actionable part of a constraint violation — which key collided — never reaches the caller.

For parity: postgrest-js names this property details, matching the wire key.

Verification

Reverting just the CodingKeys block fails the new test with the exact user-visible symptom:

Expectation failed: (error.detail → nil) == "Key (id)=(1) already exists."
  • swift test --filter "HelpersTests|PostgRESTTests" — 223 tests pass
  • swift package diagnose-api-breaking-changes origin/main — no breaking changes in any module
  • ./scripts/format.sh — no-op

Two notes for review

Encoding changes too. PostgrestError is public Codable, so it now writes "details" where it previously wrote "detail". Nothing in the SDK encodes this type, and the server is the only realistic producer, so symmetric round-tripping seems correct — but it is a behavior change for anyone who persisted an error with an older version. Happy to restrict the fix to a custom init(from:) and leave encoding alone if you'd rather avoid that.

I did not rename detaildetails. Full naming parity with postgrest-js would be source-breaking for every user reading error.detail. Mapping the coding key fixes the bug without touching the public surface.

PostgREST sends the detail text under the "details" key, but PostgrestError
declares the property as "detail" with no CodingKeys, and the shared decoder
sets no key strategy. Every PostgREST error therefore lost its detail text.

Map detail to the "details" wire key so the value survives decoding, and
encoding round-trips to the same shape.
@AndroidPoet
AndroidPoet requested review from a team and grdsdev as code owners July 31, 2026 10:54
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

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: dc81d0a1-06eb-461b-bc7c-7a6e8aa611b1

📥 Commits

Reviewing files that changed from the base of the PR and between 9b3649c and 5b14562.

📒 Files selected for processing (1)
  • dictionary.txt
🚧 Files skipped from review as they are similar to previous changes (1)
  • dictionary.txt

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Standardized API error information under the details field for consistent decoding and encoding.
    • Preserved compatibility for existing integrations using the deprecated detail name.
  • Bug Fixes

    • Improved error handling by consistently mapping error information through the expected details field.
  • Tests

    • Added coverage for decoding, encoding, and backward-compatible access to error details.

Walkthrough

PostgrestError now uses the public details property for the PostgREST details JSON field. The deprecated detail accessor and initializer preserve compatibility. Tests verify decoding, encoding, omission of a local detail key, and compatibility access through detail. SDK compliance metadata now lists PostgrestError.details, and the dictionary includes pkey.


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.

@grdsdev grdsdev 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.

Please, add a new details field to the error structure and deprecate the old detail, make detail a getter of the new details.

var detail: String? {
  get { details }
}

No need to worry about someone storing the error type (which will break).

Renames the stored property to match the PostgREST wire key and the
postgrest-js naming, keeping detail as a deprecated getter so existing
call sites continue to compile.
@AndroidPoet

Copy link
Copy Markdown
Contributor Author

Done in 6d947c1details is now the stored property and detail is a deprecated getter:

/// Additional detail about the error, as returned by PostgREST in the `details` field.
public let details: String?

@available(*, deprecated, renamed: "details")
public var detail: String? { details }

Renaming the stored property means the synthesized CodingKeys already match the wire format, so the explicit CodingKeys block from the first commit is gone entirely.

One judgement call I'd like your read on: the public initializer also took a detail: label, so I deprecated that alongside the property rather than silently changing the label:

@available(*, deprecated, renamed: "init(details:hint:code:message:)")
public init(detail: String?, hint: String? = nil, code: String? = nil, message: String)

It has no default value on detail:, so it can't become ambiguous with the new initializer. Happy to drop it if you'd rather not carry the extra overload — you said not to worry about breakage, and I wasn't sure whether that extended to construction as well as storage.

swift package diagnose-api-breaking-changes origin/main reports no breaking changes in any module, and swift test --filter "HelpersTests|PostgRESTTests" passes 224 tests, including one that asserts the deprecated getter still forwards.

@coveralls

coveralls commented Jul 31, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 31087395821

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage decreased (-0.2%) to 83.826%

Details

  • Coverage decreased (-0.2%) from the base build.
  • Patch coverage: 3 uncovered changes across 1 file (2 of 5 lines covered, 40.0%).
  • 35 coverage regressions across 5 files.

Uncovered Changes

File Changed Covered %
Sources/Helpers/SharedModels/PostgrestError.swift 5 2 40.0%

Coverage Regressions

35 previously-covered lines in 5 files lost coverage.

File Lines Losing Coverage Coverage
Sources/Auth/AuthClientConfiguration.swift 21 60.38%
Sources/Helpers/Version.swift 6 0.0%
Sources/RealtimeV2/PushV2.swift 6 83.33%
Sources/Auth/AuthAdminOAuth.swift 1 97.89%
Sources/Auth/AuthAdmin.swift 1 96.4%

Coverage Stats

Coverage Status
Relevant Lines: 10084
Covered Lines: 8453
Line Coverage: 83.83%
Coverage Strength: 40.19 hits per line

💛 - Coveralls

@grdsdev

grdsdev commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Please fix both Spell check and Validate SDK Compliance failing checks.

…ix spell check

- Add pkey to dictionary.txt (Unknown word in PostgrestErrorTests.swift)
- Register PostgrestError.details under database.query.from_table in
  sdk-compliance.yaml, since it's a new public symbol and no dedicated
  error-handling feature exists yet in the canonical registry
@grdsdev
grdsdev self-requested a review August 6, 2026 17:51
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.

3 participants