Skip to content

fix: contain exceptions thrown by consumer onError callback - #13

Merged
adeelraza merged 1 commit into
mainfrom
claude/onerror-guard-issue-9
Jul 28, 2026
Merged

fix: contain exceptions thrown by consumer onError callback#13
adeelraza merged 1 commit into
mainfrom
claude/onerror-guard-issue-9

Conversation

@adeelraza

Copy link
Copy Markdown
Contributor

Summary

Fixes #9 — a consumer onError callback that throws escapes the wrapper as an unhandled promise rejection.

fail() invokes the consumer's onError unguarded. Since fail is used as the terminal .catch handler of the serialized mount/reset chain, a throw inside onError rejects chainRef.current with no downstream handler → unhandled promise rejection.

It also has a consequence the original report didn't note: it poisons the serialized chain, violating the invariant the code documents (// Every link ends in .catch so a rejection never poisons it.). Once chainRef is left rejected, subsequent mount/reset .then links are silently skipped — later image changes are dropped and the consumer may be re-notified with a stale error.

Fix

Wrap the onError call in try/catch and route a callback exception to console.error, so the diagnostic path can never become a new failure. The original error still reaches the consumer; callback exceptions can't escape.

Severity note

This only triggers when the consumer's own onError throws (a misbehaving void callback), so it does not affect well-behaved callers. The fix is included because it is nearly free and makes the code's documented no-poison invariant actually hold.

Test plan

  • npm test — 41 passing, including a new regression test ('contains a throwing onError without poisoning the chain') that asserts the throw is swallowed and the chain still resets afterward. Verified the test fails (unhandled rejection) with the guard removed.

fail() runs as the terminal .catch of the serialized mount/reset chain.
A consumer onError that threw would reject chainRef.current, producing
an unhandled promise rejection and poisoning the chain so every
subsequent mount/reset link was silently skipped — violating the
documented invariant that a rejection never poisons the chain.

Wrap the onError call in try/catch and route a callback exception to
console.error so the diagnostic path can never become a new failure.

Closes #9
@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-image-editor Ready Ready Preview, Comment Jul 28, 2026 2:23pm

Request Review

@adeelraza
adeelraza merged commit fb8be37 into main Jul 28, 2026
9 checks passed
@adeelraza
adeelraza deleted the claude/onerror-guard-issue-9 branch July 28, 2026 14:25
@adeelraza adeelraza mentioned this pull request Jul 28, 2026
5 tasks
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.

Exceptions thrown inside onError escape the wrapper and result in an unhandled promise rejection

1 participant