Skip to content

Add error boundary to isolate extension crashes from main app#1964

Merged
yujonglee merged 2 commits intomainfrom
devin/1764300232-fix-extension-error-boundary
Nov 28, 2025
Merged

Add error boundary to isolate extension crashes from main app#1964
yujonglee merged 2 commits intomainfrom
devin/1764300232-fix-extension-error-boundary

Conversation

@yujonglee
Copy link
Contributor

@yujonglee yujonglee commented Nov 28, 2025

Add error boundary to isolate extension crashes from main app

Summary

Adds a local ExtensionErrorBoundary component that wraps extension content, preventing extension errors from crashing the entire app view. When an extension throws an error, users now see a contained error message with a "Try again" button instead of the global "Something went wrong" screen.

The original issue reported was a useStore is undefined error when opening the hello-world extension. Investigation revealed this is likely caused by a stale extension bundle on the user's machine (the current source code doesn't use useStore). This PR addresses the error isolation requirement - the user may still need to reinstall the extension to fix the root cause.

Updates since last revision

  • Merged with main and resolved conflict to integrate error boundary with the new iframe-based extension system
  • Error boundary now wraps the extension iframe component

Review & Testing Checklist for Human

  • Test extension error isolation: Open an extension that throws an error and verify the error is contained within the extension tab (not crashing the whole app)
  • Test retry functionality: Click "Try again" and verify the extension attempts to reload
  • Verify styling: Confirm the error UI (amber warning icon, error message box) matches the app's design

Test Plan

  1. Install the hello-world extension (run pnpm run build:hello-world && pnpm run install:dev in /extensions)
  2. Open the extension via Profile menu
  3. If it crashes, verify the error is isolated to the extension tab
  4. Click "Try again" and verify it attempts to reload

Notes

  • The root cause of the useStore error appears to be a stale extension bundle. The user should run pnpm run install:dev in the extensions directory to reinstall with the latest build.
  • Uses React class component for error boundary (required by React's error boundary API)
  • Important: React error boundaries catch rendering errors in the parent component. Errors that occur inside the iframe itself (in extension code) are isolated by the iframe sandbox, not by this error boundary.

Link to Devin run: https://app.devin.ai/sessions/02ea0bd1a5d74223b3babd724f7ace9c
Requested by: yujonglee (@yujonglee)

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Nov 28, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit 8061d75
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/69291b92e7a04e0008b08fab
😎 Deploy Preview https://deploy-preview-1964--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Nov 28, 2025

Deploy Preview for hyprnote-storybook ready!

Name Link
🔨 Latest commit 8061d75
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/69291b92c4294f0008cb954f
😎 Deploy Preview https://deploy-preview-1964--hyprnote-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 28, 2025

📝 Walkthrough

Walkthrough

The changes enhance the extensions tab UI with error resilience by introducing an ExtensionErrorBoundary component that captures rendering errors from extension components. A retry mechanism allows users to remount extensions after failures via state-driven remounting logic.

Changes

Cohort / File(s) Summary
Extensions Error Handling
apps/desktop/src/components/main/body/extensions/index.tsx
Added ExtensionErrorBoundary component for error capture and display; introduced retryKey state and handleRetry handler to enable retry-based remounting of extension components; expanded imports to include AlertTriangleIcon and React type utilities

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Focus on ExtensionErrorBoundary implementation logic and error state rendering
  • Verify retryKey state management and remount triggering behavior
  • Confirm error UI displays appropriate extension id and error messaging

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding an error boundary to prevent extension crashes from affecting the main app.
Description check ✅ Passed The PR description is directly related to the changeset, explaining the error boundary implementation, retry mechanism, and testing procedures.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/1764300232-fix-extension-error-boundary

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (2)
apps/desktop/src/components/main/body/extensions/index.tsx (2)

1-90: Error boundary implementation is solid; retry state reset is slightly redundant

  • The ExtensionErrorBoundary class follows the standard React error-boundary pattern (getDerivedStateFromError, local hasError flag, and a clear fallback UI with extension id and message). Imports for Component/ReactNode and AlertTriangleIcon are correct and used appropriately.
  • Because the boundary is keyed at the call site (key={retryKey}), changing retryKey already forces a full unmount/remount of the boundary and its children. The handleRetry call to this.setState({ hasError: false, error: null }) is therefore redundant in practice—you could simplify handleRetry to just call this.props.onRetry() if you like, keeping behavior the same.

This is a nit; current code is correct and safe as-is.


161-245: Retry key wiring correctly remounts extensions; behavior separation from loader looks good

  • Using retryKey state plus key={retryKey} on ExtensionErrorBoundary is an effective way to remount the extension subtree on “Try again” without re-invoking loadExtensionUI. That cleanly separates initial load failures (handled by the loader + “failed to load” UI) from runtime render errors (handled by the boundary).
  • Excluding retryKey from the useEffect dependency array is appropriate here, since a retry should not cause the loader to re-run—only to re-mount the already-registered LoadedComponent.
  • If you ever decide that retrying should also re-run the loader (e.g., for transient dynamic-import failures), you could introduce a separate loadVersion key that’s included in the effect deps and also used as the boundary key.

Also nice that this continues to use Reorder from motion/react and cn([...]) as per the repo’s guidelines. Based on learnings, this aligns with the preferred motion and className patterns.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 15f05db and fce37d3.

📒 Files selected for processing (1)
  • apps/desktop/src/components/main/body/extensions/index.tsx (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/components/main/body/extensions/index.tsx
🧠 Learnings (1)
📚 Learning: 2025-11-24T16:32:19.706Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:19.706Z
Learning: Applies to **/*.{ts,tsx} : Use `motion/react` instead of `framer-motion`.

Applied to files:

  • apps/desktop/src/components/main/body/extensions/index.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
  • GitHub Check: ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: ci (macos, depot-macos-14)
  • GitHub Check: ci (linux, depot-ubuntu-22.04-8)

…e-based extension system

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@yujonglee yujonglee merged commit 2f7eb99 into main Nov 28, 2025
11 of 13 checks passed
@ComputelessComputer ComputelessComputer deleted the devin/1764300232-fix-extension-error-boundary branch December 14, 2025 15:20
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