Skip to content

fix(desktop): show error toast when external URL fails to open#583

Merged
Kitenite merged 1 commit intomainfrom
silent-failing
Jan 4, 2026
Merged

fix(desktop): show error toast when external URL fails to open#583
Kitenite merged 1 commit intomainfrom
silent-failing

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Jan 3, 2026

Summary

  • Fix silent failure when clicking "Navigate to..." to open external URLs in browser
  • Add proper error handling and user feedback via toast notifications

Changes

  • openUrl tRPC mutation now returns { success, error } instead of void
  • Added .catch() handlers to fire-and-forget shell.openExternal() calls
  • Terminal URL click handler shows toast notification on failure

Fixes #561

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling and logging when opening external URLs; failures are now caught and reported.
    • Server-side call now returns structured errors on failure to open URLs.
    • Added user-facing notifications (toasts) to inform users when opening external URLs fails.
    • Existing navigation behavior for external http(s) links is preserved.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 3, 2026

📝 Walkthrough

Walkthrough

Added explicit error handling and user feedback when opening external URLs: Electron shell calls now log failures, the TRPC mutation wraps shell.openExternal in try/catch and throws a TRPCError on failure, and the renderer shows a toast error when the open fails. (46 words)

Changes

Cohort / File(s) Summary
Electron shell handlers
apps/desktop/src/lib/electron-app/factories/app/setup.ts, apps/desktop/src/lib/electron-app/factories/windows/create.ts
shell.openExternal(url) calls now include .catch(...) to log errors instead of leaving the promise unhandled. Control flow for http(s) navigation remains unchanged.
TRPC external router
apps/desktop/src/lib/trpc/routers/external/index.ts
openUrl mutation now wraps shell.openExternal(input) in try/catch; on error it logs and throws a TRPCError (code: INTERNAL_SERVER_ERROR) with the error message. No exported signatures changed.
Renderer — Terminal helpers
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
Added toast.error(...) to surface failures to users when URL open fails; existing console/error logging remains.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Renderer
  participant TRPC as "TRPC Procedure"
  participant Main as "Electron Main"
  participant Shell as "shell.openExternal"
  Note over Renderer,TRPC `#D3EAFD`: User action triggers open URL
  Renderer->>TRPC: call external.openUrl(input)
  TRPC->>Main: invoke shell.openExternal(input)
  Main->>Shell: shell.openExternal(url)
  alt success
    Shell-->>Main: resolved
    Main-->>TRPC: success
    TRPC-->>Renderer: success response
  else failure
    Shell-->>Main: rejected (error)
    Main-->>Main: log error (.catch)
    Main-->>TRPC: throw TRPCError (INTERNAL_SERVER_ERROR)
    TRPC-->>Renderer: procedure error
    Renderer->>Renderer: show toast.error(error.message)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I nudged the link and gave a hop,
If opening failed, I sounded a pop—
A toast for the trouble, logs for the tail,
From renderer to main, we followed the trail. 🥕✨

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 (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and specifically describes the main change: adding error toast notifications when external URL opening fails.
Description check ✅ Passed The PR description covers the key changes (error handling, toast notifications, return value change) and references the linked issue, though it doesn't follow the template sections.
Linked Issues check ✅ Passed The PR addresses issue #561 by adding error handling to shell.openExternal calls and implementing toast notifications to show errors when URL opening fails.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the silent failure issue and adding error handling for external URL opening, with no unrelated modifications detected.
✨ Finishing touches
  • 📝 Generate docstrings

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
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: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a818bc2 and b1e0002.

📒 Files selected for processing (4)
  • apps/desktop/src/lib/electron-app/factories/app/setup.ts
  • apps/desktop/src/lib/electron-app/factories/windows/create.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
🧰 Additional context used
📓 Path-based instructions (5)
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc
Use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from @trpc/server/observable instead of async generators, as the library explicitly checks isObservable(result) and throws an error otherwise

Files:

  • apps/desktop/src/lib/electron-app/factories/app/setup.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/lib/electron-app/factories/windows/create.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid using any type - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness

Files:

  • apps/desktop/src/lib/electron-app/factories/app/setup.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/lib/electron-app/factories/windows/create.ts
apps/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Drizzle ORM for all database operations - never use raw SQL

Files:

  • apps/desktop/src/lib/electron-app/factories/app/setup.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/lib/electron-app/factories/windows/create.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for formatting and linting - run at root level with bun run lint:fix or biome check --write

Files:

  • apps/desktop/src/lib/electron-app/factories/app/setup.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/lib/electron-app/factories/windows/create.ts
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.662Z
Learning: Boundary layers (tRPC procedures, API routes) own error handling - domain utilities return data or throw specific errors
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.662Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Use TRPCError with appropriate error codes: NOT_FOUND, UNAUTHORIZED, FORBIDDEN, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED
📚 Learning: 2026-01-02T06:50:28.662Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.662Z
Learning: Applies to apps/desktop/src/lib/electron-router-dom.ts : Do not import Node.js modules like node:path or dotenv in electron-router-dom.ts and similar shared files - they run in both main and renderer processes

Applied to files:

  • apps/desktop/src/lib/electron-app/factories/app/setup.ts
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2026-01-02T06:50:28.662Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.662Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Use TRPCError with appropriate error codes: NOT_FOUND, UNAUTHORIZED, FORBIDDEN, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
⏰ 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). (1)
  • GitHub Check: Build
🔇 Additional comments (4)
apps/desktop/src/lib/electron-app/factories/windows/create.ts (1)

12-14: LGTM! Good defensive error handling.

The .catch() handler properly logs external URL opening failures with context, following the prefixed console logging pattern.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (2)

1-1: LGTM! Toast import for user feedback.

The toast import enables user-facing error notifications when URL opening fails.


137-152: User feedback implementation looks good, but dual-path handling adds complexity.

The error handling correctly covers both mutation response errors and mutation rejection. However, the dual-path pattern (.then() checking result.success + .catch() for rejection) is necessary only because the openUrl mutation returns a structured result instead of following the standard tRPC error pattern.

The implementation works correctly and provides good user feedback with toast notifications and detailed error logging.

Note: If the openUrl mutation were refactored to throw TRPCError on failure (per tRPC best practices), this could be simplified to a single .catch() handler. See comment on apps/desktop/src/lib/trpc/routers/external/index.ts.

apps/desktop/src/lib/electron-app/factories/app/setup.ts (1)

61-63: LGTM! Consistent error handling.

The .catch() handler properly logs external URL opening failures, consistent with the pattern used in create.ts.

Comment thread apps/desktop/src/lib/trpc/routers/external/index.ts Outdated
- Add proper error handling to shell.openExternal() calls
- Return success/error from openUrl tRPC mutation
- Show toast notification when URL opening fails
- Log errors with context for debugging

Fixes #561
Copy link
Copy Markdown
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 (1)
apps/desktop/src/lib/trpc/routers/external/index.ts (1)

32-32: Consider adding error handling for shell.openPath for consistency.

shell.openPath returns a Promise<string> where a non-empty string indicates an error message. Currently, this error is silently ignored. For consistency with the new openUrl error handling, consider checking the result:

-	await shell.openPath(filePath);
+	const error = await shell.openPath(filePath);
+	if (error) {
+		console.error("[external/openPathInApp] Failed to open path:", filePath, error);
+		throw new TRPCError({
+			code: "INTERNAL_SERVER_ERROR",
+			message: error,
+		});
+	}

This would provide consistent error feedback across all external operations, though it's outside the immediate scope of this PR.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1e0002 and 465f439.

📒 Files selected for processing (4)
  • apps/desktop/src/lib/electron-app/factories/app/setup.ts
  • apps/desktop/src/lib/electron-app/factories/windows/create.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/desktop/src/lib/electron-app/factories/app/setup.ts
  • apps/desktop/src/lib/electron-app/factories/windows/create.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
🧰 Additional context used
📓 Path-based instructions (4)
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc
Use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from @trpc/server/observable instead of async generators, as the library explicitly checks isObservable(result) and throws an error otherwise

Files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid using any type - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness

Files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
apps/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Drizzle ORM for all database operations - never use raw SQL

Files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for formatting and linting - run at root level with bun run lint:fix or biome check --write

Files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.662Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Use TRPCError with appropriate error codes: NOT_FOUND, UNAUTHORIZED, FORBIDDEN, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED
📚 Learning: 2026-01-02T06:50:28.662Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.662Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Use TRPCError with appropriate error codes: NOT_FOUND, UNAUTHORIZED, FORBIDDEN, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from `trpc/server/observable` instead of async generators, as the library explicitly checks `isObservable(result)` and throws an error otherwise

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2026-01-02T06:50:28.662Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.662Z
Learning: Applies to apps/api/**/*.{ts,tsx} : tRPC procedures and API route handlers should validate and delegate; keep orchestrators thin

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2026-01-02T06:50:28.662Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.662Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Extract business logic from tRPC procedures into utility functions when logic exceeds ~50 lines, is used by multiple procedures, or needs independent testing

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2026-01-02T06:50:28.662Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.662Z
Learning: Boundary layers (tRPC procedures, API routes) own error handling - domain utilities return data or throw specific errors

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
⏰ 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). (1)
  • GitHub Check: Build
🔇 Additional comments (2)
apps/desktop/src/lib/trpc/routers/external/index.ts (2)

2-2: LGTM!

The TRPCError import is correctly added to support the new error handling pattern. This follows the coding guidelines for using tRPC error handling in boundary layers.


41-53: LGTM! Error handling follows tRPC conventions and coding guidelines.

The implementation correctly:

  • Wraps shell.openExternal in try/catch
  • Uses prefixed console logging with context ([external/openUrl])
  • Throws TRPCError with INTERNAL_SERVER_ERROR code per coding guidelines
  • Extracts error message with proper type narrowing

This addresses the PR objective of surfacing errors when opening external URLs fails. Based on learnings, boundary layers own error handling by throwing typed errors.

@Kitenite Kitenite merged commit ba1a112 into main Jan 4, 2026
4 of 5 checks passed
@Kitenite Kitenite deleted the silent-failing branch January 4, 2026 00:57
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 4, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch
  • ⚠️ Electric Fly.io app

Thank you for your contribution! 🎉

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.

[bug] “Navigate to …” (warning prompt) fails silently instead of opening browser tab

1 participant