Skip to content

Fix voting/commenting#3115

Merged
feruzm merged 6 commits intodevelopmentfrom
optimis
Feb 18, 2026
Merged

Fix voting/commenting#3115
feruzm merged 6 commits intodevelopmentfrom
optimis

Conversation

@feruzm
Copy link
Copy Markdown
Member

@feruzm feruzm commented Feb 18, 2026

Summary by CodeRabbit

  • Chores

    • Bumped two public dependencies to newer patch versions.
  • Bug Fixes

    • Improved diagnostics and user guidance for transaction date/expiration errors.
    • Ensured waves/comments refresh correctly when new comments arrive.
    • Stabilized mobile posting authorization to avoid unsafe optimization paths.
  • Improvements

    • Centralized media-picker error reporting with richer context and cancellation handling.
    • Improved submission flow to better handle missing accounts and posting-authority errors.
  • Localization

    • Added a server-change hint to date-error messaging.

@feruzm feruzm marked this pull request as draft February 18, 2026 16:04
@feruzm feruzm marked this pull request as ready for review February 18, 2026 16:04
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 18, 2026

Warning

Rate limit exceeded

@feruzm has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 48 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Bumps two dependencies, adds dsteem/Hive date-error detection and diagnostics with consistent TAPOS client usage, enhances waves comment-cache invalidation, disables mobile posting-authorization optimization, centralizes media-picker error reporting, and hardens dsteem error extraction.

Changes

Cohort / File(s) Summary
Dependencies
package.json
Bump @ecency/render-helper ^2.4.14 → ^2.4.17 and @ecency/sdk ^2.0.3 → ^2.0.4.
Hive broadcast & diagnostics
src/providers/hive/dhive.ts, src/utils/dsteemUtils.ts, src/config/locales/en-US.json
Detects dsteem date-related errors, collect date/TAPOS diagnostics, attach diagnostics/tags to Sentry, use same client for TAPOS data, and add server hint locale string; error-stack extraction hardened.
Waves / comment cache invalidation
src/providers/queries/postQueries/wavesQueries.ts
When recent-cache updates within 5s originate from a comment, walk comment ancestry to find the waves container and invalidate its GET query (invalidate-only, no optimistic write).
Mobile platform adapter
src/providers/sdk/mobilePlatformAdapter.ts
Disable mobile token-first posting-authorization optimization (hasPostingAuthorization now always false on mobile) and add legacy-bridge invalidation to target waves queries when entry keys are invalidated.
Quick post submitter
src/components/quickPostModal/usePostSubmitter.ts
Add guard if no account, wrap posting-authority flow in try/catch/finally, await recursive submit, and centralize isSubmitting reset in finally.
Media picker error handling
src/utils/mediaPickerError.ts, src/components/uploadsGalleryModal/..., src/containers/profileEditContainer.tsx, src/screens/chats/container/chatThreadContainer.tsx
New isMediaPickerCancellation and reportMediaPickerError; replace ad-hoc cancellation checks, report non-cancellation errors to Sentry with feature/action/mediaType, and update UI handlers to pass context.
Uploads gallery / speak uploader
src/components/uploadsGalleryModal/container/uploadsGalleryModal.tsx, src/components/uploadsGalleryModal/children/speakUploaderModal.tsx
Centralize picker error reporting, pass action/mediaType context, adjust permission-dialog action naming and flows.

Sequence Diagram(s)

sequenceDiagram
  participant UI as App / UI
  participant Dhive as dhive Client
  participant Hive as Hive API Server
  participant SDK as ecency SDK
  participant Sentry as Sentry

  UI->>Dhive: sendHiveOperations(ops)
  Dhive->>Dhive: fetch TAPOS via same client
  Dhive->>Hive: broadcast_transaction
  alt success
    Hive-->>Dhive: success
    Dhive-->>UI: success
  else date-related error
    Hive-->>Dhive: error (trx.expiration / transaction expiration)
    Dhive->>Dhive: isDsteemDateError(error) => true
    Dhive->>Dhive: getDateErrorDiagnostics() (local time, tz, client head, sdk head, skew)
    Dhive->>Sentry: captureException(error + dateDiagnostics) with tag error_type=dsteem_date_error
    Dhive-->>UI: return error with diagnostics
  else other error
    Dhive->>Sentry: captureException(error)
    Dhive-->>UI: return error
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

deploy-pr-build

Poem

🐰 Hopped through code where timestamps sleep,

I sniffed the expiry buried deep.
Waves refreshed when comments call,
Mobile skips the token ball.
Sentry logs and servers wink — hop on, let's ship the link!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The pull request title 'Fix voting/commenting' is vague and does not clearly summarize the actual changes. The changeset includes dependency updates, date error handling improvements, media picker error reporting, and query cache handling—none of which directly relate to voting or commenting fixes. Revise the title to reflect the primary changes, such as 'Improve error diagnostics and media picker error handling' or break into multiple focused PRs if addressing different concerns.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch optimis

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/providers/sdk/mobilePlatformAdapter.ts (1)

43-44: ⚠️ Potential issue | 🔴 Critical

getAccountFullQueryOptions is used but not imported — TypeScript compile error.

Line 43 references getAccountFullQueryOptions(username) inside the getUser method, but the import from @ecency/sdk is missing. This will fail TypeScript compilation with "Cannot find name 'getAccountFullQueryOptions'".

🐛 Proposed fix: restore the missing import
 import type { PlatformAdapter } from '@ecency/sdk';
+import { getAccountFullQueryOptions } from '@ecency/sdk';

Alternatively, if getUser is no longer needed by the SDK (e.g. because hasPostingAuthorization now short-circuits before any account lookup), the entire getUser implementation could be updated to return undefined immediately:

 getUser: async (username: string) => {
-  return queryClient.getQueryData(getAccountFullQueryOptions(username).queryKey);
+  return undefined;
 },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/sdk/mobilePlatformAdapter.ts` around lines 43 - 44, The getUser
implementation calls getAccountFullQueryOptions(username) but that symbol is not
imported, causing a TypeScript error; fix by adding an import for
getAccountFullQueryOptions from '@ecency/sdk' at the top of the file, or if
getUser should no longer perform lookups, change the getUser method (the
function named getUser in mobilePlatformAdapter.ts) to short-circuit and return
undefined instead of calling getAccountFullQueryOptions/getQueryData—pick one
approach and apply it consistently.
🧹 Nitpick comments (2)
src/providers/hive/dhive.ts (1)

124-137: message.includes('expiration') in isDsteemDateError is too broad.

The catch-all 'expiration' substring (line 134) would match unrelated errors — e.g., HiveSigner token-expiry messages, OAuth session expiry — causing getDateErrorDiagnostics to make two unnecessary RPC calls and incorrectly tagging those errors as dsteem_date_error in Sentry. The more specific checks ('trx.expiration', 'transaction expiration', 'trx_expiration') already cover the known Hive transaction date error patterns.

♻️ Suggested fix
  return (
    message.includes('trx.expiration') ||
    message.includes('transaction expiration') ||
-   message.includes('expiration') ||
    message.includes('trx_expiration')
  );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/hive/dhive.ts` around lines 124 - 137, The isDsteemDateError
predicate is too broad because the generic message.includes('expiration') causes
unrelated errors to be classified as dsteem_date_error and triggers extra RPC
calls in getDateErrorDiagnostics; update isDsteemDateError to remove the generic
'expiration' substring check and only check the specific patterns already
present (e.g., 'trx.expiration', 'transaction expiration', 'trx_expiration' and
the jse_info.code 4030100), so that only known Hive transaction date errors are
matched.
src/providers/queries/postQueries/wavesQueries.ts (1)

126-145: _injectCommentCache is a misleading name — the function invalidates rather than injects.

Unlike _injectPostCache which directly mutates query data (optimistic update), this function only calls queryClient.invalidateQueries, which triggers a full re-fetch. The name implies writing something into the cache, which it doesn't do.

♻️ Suggested rename
-  const _injectCommentCache = (commentPath: string) => {
+  const _invalidateContainerForComment = (commentPath: string) => {

And the call site:

-          _injectCommentCache(lastCacheUpdate.postPath);
+          _invalidateContainerForComment(lastCacheUpdate.postPath);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/queries/postQueries/wavesQueries.ts` around lines 126 - 145,
Function _injectCommentCache is misnamed because it does not write to cache but
only invalidates; rename it to reflect behavior (e.g.,
invalidateCommentWaveCache or invalidateWaveContainerForComment) and update all
call sites (places that call _injectCommentCache) accordingly. Inside the
renamed function keep the same logic that derives parentPath from
_cachedComment, reads wavesIndexCollection.current[parentPath], finds
_containerIndex via activePermlinks.indexOf(_containerPermlink) and calls
queryClient.invalidateQueries({ queryKey: [QUERIES.WAVES.GET, host,
_containerPermlink, _containerIndex] }). Also consider adding a short comment
that this is an invalidate-only path to distinguish it from _injectPostCache
which performs optimistic cache writes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/utils/dsteemUtils.ts`:
- Line 31: The hard-coded English string in parts.push('You can also try
changing API Server in Settings > Server.'); bypasses i18n; replace that literal
with intl.formatMessage({ id: 'dsteem.date_error.server_hint' }) in the same
function (where other strings use intl.formatMessage) and then add the key
dsteem.date_error.server_hint with translated values to each locale file so
non-English users see the localized hint.

---

Outside diff comments:
In `@src/providers/sdk/mobilePlatformAdapter.ts`:
- Around line 43-44: The getUser implementation calls
getAccountFullQueryOptions(username) but that symbol is not imported, causing a
TypeScript error; fix by adding an import for getAccountFullQueryOptions from
'@ecency/sdk' at the top of the file, or if getUser should no longer perform
lookups, change the getUser method (the function named getUser in
mobilePlatformAdapter.ts) to short-circuit and return undefined instead of
calling getAccountFullQueryOptions/getQueryData—pick one approach and apply it
consistently.

---

Nitpick comments:
In `@src/providers/hive/dhive.ts`:
- Around line 124-137: The isDsteemDateError predicate is too broad because the
generic message.includes('expiration') causes unrelated errors to be classified
as dsteem_date_error and triggers extra RPC calls in getDateErrorDiagnostics;
update isDsteemDateError to remove the generic 'expiration' substring check and
only check the specific patterns already present (e.g., 'trx.expiration',
'transaction expiration', 'trx_expiration' and the jse_info.code 4030100), so
that only known Hive transaction date errors are matched.

In `@src/providers/queries/postQueries/wavesQueries.ts`:
- Around line 126-145: Function _injectCommentCache is misnamed because it does
not write to cache but only invalidates; rename it to reflect behavior (e.g.,
invalidateCommentWaveCache or invalidateWaveContainerForComment) and update all
call sites (places that call _injectCommentCache) accordingly. Inside the
renamed function keep the same logic that derives parentPath from
_cachedComment, reads wavesIndexCollection.current[parentPath], finds
_containerIndex via activePermlinks.indexOf(_containerPermlink) and calls
queryClient.invalidateQueries({ queryKey: [QUERIES.WAVES.GET, host,
_containerPermlink, _containerIndex] }). Also consider adding a short comment
that this is an invalidate-only path to distinguish it from _injectPostCache
which performs optimistic cache writes.

Comment thread src/utils/dsteemUtils.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/quickPostModal/usePostSubmitter.ts (1)

55-214: ⚠️ Potential issue | 🟡 Minor

Surface posting-authority prompt failures to the user.
The inner catch returns false silently, so users get no feedback when the prompt fails. Consider rethrowing to trigger the outer alert (or alert here).

Suggested fix
        } catch (error) {
          console.warn('Failed to grant posting authority:', error);
-          return false;
+          throw error;
        } finally {
          setPostingAuthorityPromptShown(false);
        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/quickPostModal/usePostSubmitter.ts` around lines 55 - 214, The
inner catch inside the posting-authority prompt flow swallows errors (in the
block around shouldPromptPostingAuthority / getPostingAuthorityPromptShown) so
users receive no feedback; update that catch (the one that currently logs
'Failed to grant posting authority:') to surface the failure by either calling
Alert.alert with a localized message and error details or rethrowing the error
so the outer try/catch (which shows intl.formatMessage 'alert.something_wrong')
handles it; ensure you still reset setPostingAuthorityPromptShown(false) in the
finally block and preserve the manageSubmittingState setIsSubmitting(false)
behavior.
🧹 Nitpick comments (2)
src/providers/queries/postQueries/wavesQueries.ts (1)

133-135: Optional: guard against missing parent_author/parent_permlink

If a partially-written cached comment lands in commentsCollection without parent_author or parent_permlink, parentPath becomes "undefined/undefined" — which fails the lookup silently. A one-line guard makes the intent explicit:

🛡️ Proposed defensive guard
  const parentPath = `${_cachedComment.parent_author}/${_cachedComment.parent_permlink}`;
+ if (!_cachedComment.parent_author || !_cachedComment.parent_permlink) {
+   return;
+ }
  const _containerPermlink = wavesIndexCollection.current[parentPath];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/queries/postQueries/wavesQueries.ts` around lines 133 - 135,
The code builds parentPath from _cachedComment.parent_author and parent_permlink
without checking for presence, so add a guard before constructing parentPath to
handle missing values: verify both _cachedComment.parent_author and
_cachedComment.parent_permlink are truthy and if not, set _containerPermlink to
undefined (or skip the lookup) instead of creating "undefined/undefined"; then
only compute parentPath and read wavesIndexCollection.current[parentPath] when
both fields are present to avoid silent lookup failures.
src/utils/mediaPickerError.ts (1)

9-18: Handle non-Error throws in cancellation detection.
If callers throw strings, error?.message is empty and cancellation keywords won’t match. Consider falling back to String(error).

Suggested tweak
-  const message = String(error?.message || '').toLowerCase();
+  const message = String(error?.message || error || '').toLowerCase();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/mediaPickerError.ts` around lines 9 - 18, The cancellation detector
is missing non-Error throws because message is derived only from error?.message;
update isMediaPickerCancellation to fallback to the entire error when message is
absent (use error?.message ?? error) so String(...) captures thrown strings or
other primitives, then continue using code and message checks (variables: code,
message) to test E_PICKER_CANCELLED and 'cancelled'/'canceled'. Ensure you only
change the message derivation so other logic remains the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/uploadsGalleryModal/children/speakUploaderModal.tsx`:
- Around line 28-29: The alert is still shown for user-cancelled picker actions
even though reportMediaPickerError already ignores cancellations; in both places
in speakUploaderModal.tsx where reportMediaPickerError is invoked, after calling
reportMediaPickerError check its return (or detect the cancellation from the
thrown error) and immediately return early when it indicates a user cancellation
so the alert is not shown; update both occurrences that call
reportMediaPickerError to bail out before calling alert or showing UI noise.

In `@src/components/uploadsGalleryModal/container/uploadsGalleryModal.tsx`:
- Line 18: The code currently calls reportMediaPickerError and constructs/shows
an error dialog even when the user cancelled the media picker; update each error
handler that calls reportMediaPickerError or builds the dialog (references:
reportMediaPickerError) to first check isMediaPickerCancellation(error) and
return early if true. Concretely, add a guard like "if
(isMediaPickerCancellation(err)) return;" before any reportMediaPickerError(...)
call or before assembling/showing the dialog so cancellation is short‑circuited
(apply the same change to the other occurrences noted in the diff).

In `@src/providers/queries/postQueries/wavesQueries.ts`:
- Around line 127-145: _invalidateWaveContainerForComment currently assumes
_cachedComment.parent_permlink is a top-level wave and uses
wavesIndexCollection.current[parentPath], which fails for reply-to-reply; update
the function to walk the comment ancestry via cache.commentsCollection (starting
from _cachedComment.parent_author/_cachedComment.parent_permlink) in a loop
until you find a parentPath present in wavesIndexCollection.current (or exhaust
the chain), then use that found _containerPermlink and its index in
activePermlinks to call queryClient.invalidateQueries([QUERIES.WAVES.GET, host,
_containerPermlink, _containerIndex]); this ensures nested replies trigger the
same invalidation logic as top-level replies.

---

Outside diff comments:
In `@src/components/quickPostModal/usePostSubmitter.ts`:
- Around line 55-214: The inner catch inside the posting-authority prompt flow
swallows errors (in the block around shouldPromptPostingAuthority /
getPostingAuthorityPromptShown) so users receive no feedback; update that catch
(the one that currently logs 'Failed to grant posting authority:') to surface
the failure by either calling Alert.alert with a localized message and error
details or rethrowing the error so the outer try/catch (which shows
intl.formatMessage 'alert.something_wrong') handles it; ensure you still reset
setPostingAuthorityPromptShown(false) in the finally block and preserve the
manageSubmittingState setIsSubmitting(false) behavior.

---

Nitpick comments:
In `@src/providers/queries/postQueries/wavesQueries.ts`:
- Around line 133-135: The code builds parentPath from
_cachedComment.parent_author and parent_permlink without checking for presence,
so add a guard before constructing parentPath to handle missing values: verify
both _cachedComment.parent_author and _cachedComment.parent_permlink are truthy
and if not, set _containerPermlink to undefined (or skip the lookup) instead of
creating "undefined/undefined"; then only compute parentPath and read
wavesIndexCollection.current[parentPath] when both fields are present to avoid
silent lookup failures.

In `@src/utils/mediaPickerError.ts`:
- Around line 9-18: The cancellation detector is missing non-Error throws
because message is derived only from error?.message; update
isMediaPickerCancellation to fallback to the entire error when message is absent
(use error?.message ?? error) so String(...) captures thrown strings or other
primitives, then continue using code and message checks (variables: code,
message) to test E_PICKER_CANCELLED and 'cancelled'/'canceled'. Ensure you only
change the message derivation so other logic remains the same.

Comment thread src/components/uploadsGalleryModal/children/speakUploaderModal.tsx Outdated
Comment thread src/components/uploadsGalleryModal/container/uploadsGalleryModal.tsx Outdated
Comment thread src/providers/queries/postQueries/wavesQueries.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/quickPostModal/usePostSubmitter.ts (1)

242-244: ⚠️ Potential issue | 🟡 Minor

Unguarded err.message access could throw if err is not an Error object.

This is pre-existing code, but now that _submitReply has a robust outer catch that always returns false (never throws), this catch block would only fire for errors from fetchLatestWavesContainer. If that throws a non-Error value (e.g., a string or undefined), err.message will be undefined — which is benign for Alert.alert — but if err itself is null/undefined, this line will throw an unhandled NPE.

Consider a defensive access:

Suggested fix
-      Alert.alert('Fail', err.message);
+      Alert.alert('Fail', err?.message || String(err));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/quickPostModal/usePostSubmitter.ts` around lines 242 - 244,
The catch block that calls Alert.alert('Fail', err.message) can throw if err is
null/undefined or not an Error; update the catch to defensively derive a message
(e.g., if err is an object with a message use that, else if err is a string use
it, else fall back to String(err) or a literal like 'Unknown error') and pass
that computed message to Alert.alert in place of err.message while keeping the
same return false behavior; locate the catch where Alert.alert is called in
usePostSubmitter.ts (the catch surrounding
fetchLatestWavesContainer/_submitReply) and replace the direct err.message
access with the guarded message extraction.
🧹 Nitpick comments (1)
src/utils/mediaPickerError.ts (1)

9-19: Broad substring match on message could suppress non-cancellation errors.

The message.includes('cancelled') || message.includes('canceled') checks are quite broad. If a genuine error happens to contain those substrings (e.g., "Upload was canceled by the server due to invalid format"), it would be silently swallowed. Consider tightening the match — for instance, checking for 'user cancelled' or anchoring to the known library messages — or at minimum, checking the code first and only falling back to the message match when code is empty.

That said, in the narrow context of react-native-image-crop-picker, this is unlikely to cause problems today.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/mediaPickerError.ts` around lines 9 - 19, The
isMediaPickerCancellation function currently treats any message containing
"cancelled"/"canceled" as a cancellation which can hide real errors; update
isMediaPickerCancellation to prefer checking the normalized code first (code ===
'E_PICKER_CANCELLED' || code === 'E_PICKER_CANCELLED_KEY') and only perform a
message-based fallback when code is empty/undefined, and tighten the message
check to specific, less-broad patterns (e.g., exact known library messages or
regex with word boundaries like /\b(user )?cancel(?:led|ed)\b/ or match
startsWith/equals for known phrases) so unrelated messages are not
misclassified. Ensure changes are applied within the isMediaPickerCancellation
function and preserve its return boolean behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/components/quickPostModal/usePostSubmitter.ts`:
- Around line 242-244: The catch block that calls Alert.alert('Fail',
err.message) can throw if err is null/undefined or not an Error; update the
catch to defensively derive a message (e.g., if err is an object with a message
use that, else if err is a string use it, else fall back to String(err) or a
literal like 'Unknown error') and pass that computed message to Alert.alert in
place of err.message while keeping the same return false behavior; locate the
catch where Alert.alert is called in usePostSubmitter.ts (the catch surrounding
fetchLatestWavesContainer/_submitReply) and replace the direct err.message
access with the guarded message extraction.

---

Nitpick comments:
In `@src/utils/mediaPickerError.ts`:
- Around line 9-19: The isMediaPickerCancellation function currently treats any
message containing "cancelled"/"canceled" as a cancellation which can hide real
errors; update isMediaPickerCancellation to prefer checking the normalized code
first (code === 'E_PICKER_CANCELLED' || code === 'E_PICKER_CANCELLED_KEY') and
only perform a message-based fallback when code is empty/undefined, and tighten
the message check to specific, less-broad patterns (e.g., exact known library
messages or regex with word boundaries like /\b(user )?cancel(?:led|ed)\b/ or
match startsWith/equals for known phrases) so unrelated messages are not
misclassified. Ensure changes are applied within the isMediaPickerCancellation
function and preserve its return boolean behavior.

@feruzm feruzm merged commit 29baad7 into development Feb 18, 2026
1 of 3 checks passed
@feruzm feruzm deleted the optimis branch February 18, 2026 16:58
@coderabbitai coderabbitai Bot mentioned this pull request Mar 28, 2026
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.

1 participant