Skip to content

fix: correctness fixes across gotrue, postgrest, storage, supabase and supabase_flutter#1445

Merged
spydon merged 5 commits into
mainfrom
fix/review-bugs
Jun 22, 2026
Merged

fix: correctness fixes across gotrue, postgrest, storage, supabase and supabase_flutter#1445
spydon merged 5 commits into
mainfrom
fix/review-bugs

Conversation

@spydon

@spydon spydon commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

A batch of correctness fixes found during a code review sweep. Each fix is in its own per-package commit and ships with a regression test that was verified to fail on the current main and pass with the fix.

gotrue

  • verifyOTP sent the captcha token under captchaToken inside gotrue_meta_security, but the server reads captcha_token, so the token was silently dropped. Now uses captcha_token like every other call.
  • resend checked containsKey(['message_id']) with a list argument (always false), so ResendResponse.messageId was never populated. Now uses the string key.

postgrest

  • .maybeSingle().count() with zero matching rows and no converter returned null as T where T is the non-nullable PostgrestResponse, throwing a TypeError. Now returns a response with null data and count: 0.

storage_client

  • A single MultipartFile instance was reused across retry attempts, so a retry re-finalized an already finalized file and threw a StateError instead of retrying. The request factory now builds a fresh MultipartFile per attempt.
  • Binary signed url uploads derived the content type from the full url including the ?token= query string, defeating mime lookup and falling back to application/octet-stream. Now uses the url path.
  • _removeEmptyFolders used JavaScript regex literals (/.../g) that never matched, making it a no-op. Now uses valid Dart patterns so signed url paths are normalized.

supabase

  • The headers setter rebuilt the realtime client headers from the client headers only, dropping the apikey entry present at construction. Now includes the apikey. Also removes a redundant self-spread when merging rest headers before an rpc.

supabase_flutter

  • When initialized with a custom accessToken, _restoreSessionCancellableOperation was never assigned, so dispose() threw a LateInitializationError. The field is now nullable and cancelled with a null-aware call.

Test plan

  • New and updated tests in each package, all mock based and runnable without a backend.
  • Each test was confirmed to fail on the unpatched main and pass with the fix.
  • dart analyze and dart format are clean across all changed files.

spydon added 5 commits June 22, 2026 10:05
…age id

verifyOTP sent the captcha token under `captchaToken` inside
`gotrue_meta_security`, but the server reads `captcha_token`, so the token
was silently dropped. resend checked `containsKey(['message_id'])` with a
list argument, which is always false, so `ResendResponse.messageId` was
never populated.
When `.maybeSingle().count()` matched zero rows and no converter was set,
the builder returned `null as T` where `T` is the non-nullable
`PostgrestResponse`, throwing a TypeError. It now returns a response with
null data and a count of 0, matching the converter branch.
…th normalization

A single MultipartFile instance was reused across retry attempts, so a
retry re-finalized an already finalized file and threw a StateError instead
of retrying. The request factory now builds a fresh MultipartFile per
attempt. Binary signed url uploads derived the content type from the full
url including the query string, which defeated mime lookup and fell back to
application/octet-stream; it now uses the url path. _removeEmptyFolders used
JavaScript regex literals that never matched, so it was a no-op; it now uses
valid Dart patterns.
…nt headers

The headers setter rebuilt the realtime client headers from the client
headers only, dropping the apikey entry that is present at construction. It
now includes the apikey, matching how the realtime client is built. Also
removes a redundant self-spread when merging rest headers before an rpc.
When initialized with a custom accessToken, _restoreSessionCancellableOperation
was never assigned, so dispose threw a LateInitializationError. The field is
now nullable and cancelled with a null-aware call.
@spydon spydon requested a review from a team as a code owner June 22, 2026 08:05
@spydon spydon merged commit bf31389 into main Jun 22, 2026
33 of 34 checks passed
@spydon spydon deleted the fix/review-bugs branch June 22, 2026 10:22
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