Skip to content

fix(supabase): populate EncryptedSupabaseError.encryptionError (#626)#634

Merged
coderdan merged 3 commits into
feat/eql-v3-text-search-schemafrom
fix/supabase-v2-encryption-error
Jul 13, 2026
Merged

fix(supabase): populate EncryptedSupabaseError.encryptionError (#626)#634
coderdan merged 3 commits into
feat/eql-v3-text-search-schemafrom
fix/supabase-v2-encryption-error

Conversation

@coderdan

Copy link
Copy Markdown
Contributor

Stacked on #630 (adapter package split).

Problem

The Supabase query builder's catch block hardcoded encryptionError: undefined, so the typed EncryptedSupabaseError.encryptionError field (packages/stack-supabase/src/types.ts) was always undefined — even when the caught error was an encryption failure. Callers had no way to branch on it and were forced to detect encryption failures indirectly (status === 500 && statusText === 'Encryption Error', or .throwOnError()).

Fix

  • In the base execute() catch, thread the wrapped EncryptionError through when the caught error is an EncryptionFailedError; leave encryptionError unset for plain PostgREST/API errors.
  • Tighten EncryptionFailedError.encryptionError from unknown to EncryptionError — all five throw sites already pass a result.failure/decrypted.failure.
  • The v3 dialect shares the same base execute() catch, so it's fixed for free. Its encryptionFailure helper now synthesizes an EncryptionError for the two contract-violation cases (bulk length mismatch, null envelope) that have no underlying failure object — a broken query encryption is still an encryption failure.

Tests

New supabase-encryption-error.test.ts pins, for both dialects:

  • a genuine encryption failure → error.encryptionError is populated with the underlying EncryptionError;
  • a plain (non-encryption) throw → error.encryptionError is undefined while error.message still carries the API error.

Notes

Closes #626

https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w

@coderdan coderdan requested a review from a team as a code owner July 13, 2026 03:12
@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 663cfe9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@cipherstash/stack-supabase Patch
@cipherstash/basic-example Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 041a2a8f-8672-4e39-be2e-99e1f531e761

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/supabase-v2-encryption-error

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.

Copilot AI 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.

Pull request overview

This PR fixes @cipherstash/stack-supabase so EncryptedSupabaseError.encryptionError is actually populated when an encrypt/decrypt step fails, allowing callers to branch on the underlying EncryptionError rather than relying on indirect heuristics.

Changes:

  • Thread EncryptionFailedError.encryptionError into the execute() catch-path error object (v2 + v3 via shared base behavior).
  • Tighten EncryptionFailedError.encryptionError from unknown to EncryptionError, and synthesize an EncryptionError for v3 contract-violation cases where no underlying failure exists.
  • Add regression tests asserting encryptionError is populated on real encryption failures (and remains undefined for a non-encryption throw), plus a patch changeset.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/stack-supabase/src/query-builder.ts Populate EncryptedSupabaseError.encryptionError when the caught error is an EncryptionFailedError; tighten the wrapper’s encryptionError type.
packages/stack-supabase/src/query-builder-v3.ts Narrow encryptionFailure’s cause type to EncryptionError and synthesize one when missing (contract-violation paths).
packages/stack-supabase/tests/supabase-encryption-error.test.ts Add regression coverage for #626 across v2 and v3 dialects.
.changeset/supabase-encryption-error.md Patch changeset documenting the behavioral fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/stack-supabase/__tests__/supabase-encryption-error.test.ts Outdated
@coderdan coderdan force-pushed the fix/supabase-v2-encryption-error branch 2 times, most recently from 1be835a to ef5d8c2 Compare July 13, 2026 04:11
Base automatically changed from feat/split-adapter-packages to feat/eql-v3-text-search-schema July 13, 2026 05:23
coderdan added 2 commits July 13, 2026 15:24
The query builder's catch block hardcoded `encryptionError: undefined`, so
the typed `EncryptedSupabaseError.encryptionError` field was always empty and
callers could only detect encryption failures indirectly (status/statusText
or `.throwOnError()`).

- Thread the wrapped `EncryptionError` through when the caught error is an
  `EncryptionFailedError`; leave it unset for plain PostgREST/API errors.
- Tighten `EncryptionFailedError.encryptionError` from `unknown` to
  `EncryptionError` (all five throw sites already pass a `result.failure`).
- v3 shares the base `execute()` catch; its `encryptionFailure` helper now
  synthesizes an `EncryptionError` for the contract-violation cases (bulk
  length mismatch, null envelope) that have no underlying failure object.
- Add unit coverage for both dialects: populated on a genuine encryption
  failure, absent on a plain error.

Closes #626

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
…review)

Address self-review findings on the #626 fix:

- Test coverage: the v3 test routed through the shared base `encryptModel`
  path, so the v3-specific `encryptionFailure` synthesize branch this PR adds
  was unasserted (a regression to `cause` would not have failed any test).
  Replace it with a test that drives that branch directly via a bulk
  length-mismatch and asserts `error.encryptionError` is populated. Verified
  by mutation: reverting the branch turns the test red.
- Comment: hedge the base catch-block comment — the wrapped value is the
  operation's `EncryptionError` OR, in v3, a synthesized one.
- Style: collapse the two-line same-module `errors` import into the repo's
  combined `import { type X, Y }` idiom.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
@coderdan coderdan force-pushed the fix/supabase-v2-encryption-error branch from ef5d8c2 to 0990df7 Compare July 13, 2026 05:24
…review)

Copilot flagged that the v3 synthesize branch had two no-cause call sites
(bulk length mismatch and null envelope) but only the failure-with-cause case
was covered. The length-mismatch path is now tested; add the null-envelope
path too so both no-cause call sites explicitly pin `error.encryptionError`.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
@coderdan coderdan merged commit 748e4ff into feat/eql-v3-text-search-schema Jul 13, 2026
9 checks passed
@coderdan coderdan deleted the fix/supabase-v2-encryption-error branch July 13, 2026 05:28
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.

2 participants