Skip to content

Conversation

@maparent
Copy link
Collaborator

@maparent maparent commented Dec 12, 2025

created an internalError handler that either logs to console.error or sends a report to posthog; and optionally shows a toast to the user. This should provide a pattern that combines many common use cases.

Summary by CodeRabbit

  • Bug Fixes

    • Centralized and standardized error reporting across the app, improving consistency of user-facing error notifications and reducing redundant console/email noise.
  • Chores

    • Added a unified internal error handler and refactored components to use it for richer diagnostics and safer error flows.
    • Consolidated telemetry on extension load to include version/build context for better monitoring.

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

@linear
Copy link

linear bot commented Dec 12, 2025

@supabase
Copy link

supabase bot commented Dec 12, 2025

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@maparent maparent force-pushed the eng-1135-replacing-sendmail-with-explicit-posthog-errors branch from 6e47ec6 to b581e2d Compare December 12, 2025 17:40
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

📝 Walkthrough

Walkthrough

Adds a centralized internalError utility and replaces local error-reporting (previously sendErrorEmail/console) across multiple Roam UI components and utilities with structured internalError({...}) calls; introduces a new exported internalError function.

Changes

Cohort / File(s) Summary
New core utility
apps/roam/src/utils/internalError.ts
New default-exported centralized error handler that normalizes errors, enriches context (app, graph, version, buildDate, user), captures exceptions via PostHog, optionally sends error emails, and shows a user toast when userMessage is provided.
CreateRelation & Export UI
apps/roam/src/components/CreateRelationDialog.tsx, apps/roam/src/components/Export.tsx
Removed local error helpers and sendErrorEmail usage; replaced with internalError({ error, type, userMessage?, context? }) calls and updated imports.
Canvas: Clipboard, Tldraw, store
apps/roam/src/components/canvas/Clipboard.tsx, apps/roam/src/components/canvas/Tldraw.tsx, apps/roam/src/components/canvas/useRoamStore.ts
Replaced console/sendErrorEmail/local toError patterns with internalError calls, normalized error type strings, removed .catch() wrappers after reporting, and adjusted imports.
Sync utility
apps/roam/src/utils/syncDgNodesToSupabase.ts
Replaced sendErrorEmail(...) with internalError({ error, type, context }) in failure reporting; removed prior .catch() chaining.
Admin UI
apps/roam/src/components/settings/AdminPanel.tsx
Changed onClick error path to call internalError({ error, type, sendEmail: true, forceSendInDev: true }) instead of sendErrorEmail.
App init / analytics
apps/roam/src/index.ts
Added getVersionWithDate import and moved PostHog identify/capture logic into PostHog's loaded callback to register version/buildDate/graphName and emit "Extension Loaded".

Sequence Diagram(s)

sequenceDiagram
    participant Component as Component (UI / util)
    participant internalError as internalError()
    participant PostHog as PostHog
    participant EmailSvc as sendErrorEmail
    participant Toast as ToastSystem
    participant Console as Console (dev)

    Component->>internalError: internalError({ error, type?, userMessage?, context?, sendEmail?, forceSendInDev? })
    Note right of internalError: Normalize error → Error object\nEnrich context (app, graphName, version, buildDate, username)

    alt development & not forceSendInDev
        internalError->>Console: console.error(error, enrichedContext)
    else
        internalError->>PostHog: captureException(error, enrichedContext)
        PostHog-->>internalError: ack
    end

    alt sendEmail !== false
        internalError->>EmailSvc: sendErrorEmail({ error, type, context }) 
        EmailSvc-->>internalError: ack / error
    end

    alt userMessage provided
        internalError->>Toast: show({ id, message:userMessage, intent: danger, timeout:5s })
        Toast-->>internalError: displayed
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Check PostHog capture context shape and that getVersionWithDate usage is correct in internalError.ts and index.ts.
  • Verify all previous sendErrorEmail imports/usages were removed/replaced and flagged call-sites (e.g., AdminPanel force flags) behave as intended.
  • Confirm error normalization logic (string → Error, JSON fallback) and toast behavior/timeouts.

Possibly related PRs

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'eng-1135 define internalError' clearly and specifically summarizes the main change: defining a new centralized internalError utility that replaces sendErrorEmail throughout the codebase.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f39e35c and 4056842.

📒 Files selected for processing (9)
  • apps/roam/src/components/CreateRelationDialog.tsx (4 hunks)
  • apps/roam/src/components/Export.tsx (3 hunks)
  • apps/roam/src/components/canvas/Clipboard.tsx (7 hunks)
  • apps/roam/src/components/canvas/Tldraw.tsx (2 hunks)
  • apps/roam/src/components/canvas/useRoamStore.ts (5 hunks)
  • apps/roam/src/components/settings/AdminPanel.tsx (1 hunks)
  • apps/roam/src/index.ts (1 hunks)
  • apps/roam/src/utils/internalError.ts (1 hunks)
  • apps/roam/src/utils/syncDgNodesToSupabase.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/roam/src/utils/syncDgNodesToSupabase.ts
  • apps/roam/src/components/Export.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/main.mdc)

**/*.{ts,tsx}: Use Tailwind CSS for styling where possible
When refactoring inline styles, use tailwind classes
Prefer type over interface in TypeScript
Use explicit return types for functions
Avoid any types when possible
Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use PascalCase for components and types
Use camelCase for variables and functions
Use UPPERCASE for constants
Function names should describe their purpose clearly
Prefer early returns over nested conditionals for better readability

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/settings/AdminPanel.tsx
  • apps/roam/src/index.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/internalError.ts
apps/roam/**/*.{js,ts,tsx,jsx,json}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Prefer existing dependencies from package.json when working on the Roam Research extension

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/settings/AdminPanel.tsx
  • apps/roam/src/index.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/internalError.ts
apps/roam/**/*.{ts,tsx,jsx,js,css,scss}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/settings/AdminPanel.tsx
  • apps/roam/src/index.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/internalError.ts
apps/roam/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

apps/roam/**/*.{ts,tsx,js,jsx}: Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality
Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/settings/AdminPanel.tsx
  • apps/roam/src/index.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/internalError.ts
apps/roam/**

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Implement the Discourse Graph protocol in the Roam Research extension

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/settings/AdminPanel.tsx
  • apps/roam/src/index.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/internalError.ts
🧠 Learnings (12)
📓 Common learnings
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-12-13T00:42:41.524Z
Learning: The `internalError` utility in apps/roam/src/utils/internalError.ts handles string-to-error conversion internally. Callers can pass strings directly as the error parameter without needing to convert them to Error objects first.
📚 Learning: 2025-12-13T00:42:41.524Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-12-13T00:42:41.524Z
Learning: The `internalError` utility in apps/roam/src/utils/internalError.ts handles string-to-error conversion internally. Callers can pass strings directly as the error parameter without needing to convert them to Error objects first.

Applied to files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/settings/AdminPanel.tsx
  • apps/roam/src/components/canvas/Tldraw.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/internalError.ts
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality

Applied to files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/index.ts
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/internalError.ts
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,jsx,js,css,scss} : Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/** : Implement the Discourse Graph protocol in the Roam Research extension

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/index.ts
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/index.ts
  • apps/roam/src/utils/internalError.ts
📚 Learning: 2025-06-19T19:43:43.380Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 226
File: apps/roam/src/components/settings/HomePersonalSettings.tsx:123-149
Timestamp: 2025-06-19T19:43:43.380Z
Learning: The "Fetch Embeddings for nodes" button in HomePersonalSettings.tsx is for testing purposes only, so it doesn't require production-level error handling or user feedback improvements.

Applied to files:

  • apps/roam/src/components/settings/AdminPanel.tsx
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{js,ts,tsx,jsx,json} : Prefer existing dependencies from package.json when working on the Roam Research extension

Applied to files:

  • apps/roam/src/index.ts
📚 Learning: 2025-06-22T10:40:52.752Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:18-31
Timestamp: 2025-06-22T10:40:52.752Z
Learning: In apps/roam/src/utils/getAllDiscourseNodesSince.ts, the user confirmed that querying for `?title` with `:node/title` and mapping it to the `text` field in the DiscourseGraphContent type is the correct implementation for retrieving discourse node content from Roam Research, despite it appearing to query page titles rather than block text content.

Applied to files:

  • apps/roam/src/components/canvas/Clipboard.tsx
📚 Learning: 2025-11-05T21:57:14.909Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 534
File: apps/roam/src/utils/createReifiedBlock.ts:40-48
Timestamp: 2025-11-05T21:57:14.909Z
Learning: In the discourse-graph repository, the function `getPageUidByPageTitle` from `roamjs-components/queries/getPageUidByPageTitle` is a synchronous function that returns a string directly (the page UID or an empty string if not found), not a Promise. It should be called without `await`.

Applied to files:

  • apps/roam/src/components/canvas/Clipboard.tsx
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `type` serves as the unique identifier field, not a type classification field. The interface has no `uid` or `id` field, making `node.type` the correct field to use for UID-related operations.

Applied to files:

  • apps/roam/src/components/canvas/Clipboard.tsx
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `node.type` serves as the UID field rather than having a conventional `node.uid` field. This is an unusual naming convention where the type field actually contains the unique identifier.

Applied to files:

  • apps/roam/src/components/canvas/Clipboard.tsx
🧬 Code graph analysis (1)
apps/roam/src/index.ts (1)
apps/roam/src/utils/getVersion.ts (1)
  • getVersionWithDate (9-24)
🔇 Additional comments (6)
apps/roam/src/utils/internalError.ts (1)

1-71: Centralized error utility looks correct and robust

The normalization of error, the dev/production branching, PostHog + email reporting, and optional toast behavior are all consistent and safe. Catching and logging failures from sendErrorEmail is a good addition. I don’t see correctness issues here.

apps/roam/src/components/canvas/Tldraw.tsx (1)

89-90: Tldraw error routing into internalError looks good

Forwarding the custom tldraw:error event into internalError with title and the last few actions as context is a solid integration; with lastActionsRef already bounded, payload size stays reasonable. No issues here.

Also applies to: 511-519

apps/roam/src/index.ts (1)

42-63: PostHog loaded hook + version metadata integration looks sound

Using loaded to identify the user, attach graphName, and register version / buildDate before capturing a single "Extension Loaded" event is a clean way to enrich analytics without changing the rest of the init path. No changes needed here.

apps/roam/src/components/CreateRelationDialog.tsx (1)

24-24: Error reporting in relation-identification paths is consistent and appropriate

All four guard paths now call internalError with a consistent type and clear messages, then fall back gracefully (null / []). Passing plain strings as error is fine since internalError handles string-to-Error conversion internally (based on learnings). No further changes needed.

Also applies to: 106-140, 289-292

apps/roam/src/components/canvas/useRoamStore.ts (1)

28-28: Store error handling now cleanly centralized via internalError

handleStoreError and the upgrade catch both route failures through internalError with a clear type and useful context (pageUid, snapshotSize / oldData), while also updating local error/loading state. This is a good consolidation of error paths; I don’t see functional issues here.

Also applies to: 135-158, 170-185, 302-313

apps/roam/src/components/canvas/Clipboard.tsx (1)

60-60: Clipboard error paths are now well-instrumented via internalError

The clipboard init, persistence, discourse-node fetch, and drop-node failure paths all now report through internalError with clear type labels and focused context (e.g., canvasPageTitle, clipboardBlockUid, pageTitle, uid). After logging, the code falls back safely (e.g., marking initialized or using empty lists), so behavior remains robust. The Roam query formatting change is purely cosmetic.

Also applies to: 139-152, 170-175, 191-196, 275-279, 435-440, 595-599


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

🧹 Nitpick comments (3)
apps/roam/src/components/canvas/useRoamStore.ts (1)

137-158: Remove unused errorMessage parameter.

The errorMessage parameter is no longer used after migrating to internalError, but callers still pass it (lines 172, 182). This creates dead code.

 const handleStoreError = ({
   error,
-  errorMessage,
 }: {
   error: Error;
-  errorMessage: string;
 }): void => {
   setError(error);
   setLoading(false);
   const snapshotSize = initialSnapshot
     ? JSON.stringify(initialSnapshot).length
     : 0;
   internalError({
     error,
     type: "roam-store-error",
     context: {
       pageUid,
       snapshotSize,
       ...(snapshotSize < 10000 ? { initialSnapshot } : {}),
     },
   });
 };

And update the call sites:

-handleStoreError({
-  error: e as Error,
-  errorMessage: "Failed to create TLStore",
-});
+handleStoreError({ error: e as Error });
apps/roam/src/components/CreateRelationDialog.tsx (1)

95-99: Consider passing an Error object for consistency.

While internalError handles string errors by converting them, other call sites in this PR consistently pass Error objects. For consistency and to preserve stack traces:

 internalError({
   type: "create-relation-error",
-  error:
-    "Create Relation dialog: Could not find identify node downstream",
+  error: new Error(
+    "Create Relation dialog: Could not identify node downstream",
+  ),
 });

Also note: "find identify" appears to be a typo - should be "identify" or "find".

apps/roam/src/utils/internalError.ts (1)

7-17: Add explicit return type annotation.

As per coding guidelines, functions should have explicit return types.

 const internalError = ({
   error,
   userMessage,
   type,
   context,
 }: {
   error: unknown;
   type?: string;
   userMessage?: string;
   context?: Properties;
-}) => {
+}): void => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 193e67d and 6e47ec6.

📒 Files selected for processing (7)
  • apps/roam/src/components/CreateRelationDialog.tsx (4 hunks)
  • apps/roam/src/components/Export.tsx (5 hunks)
  • apps/roam/src/components/canvas/Clipboard.tsx (7 hunks)
  • apps/roam/src/components/canvas/Tldraw.tsx (2 hunks)
  • apps/roam/src/components/canvas/useRoamStore.ts (3 hunks)
  • apps/roam/src/utils/internalError.ts (1 hunks)
  • apps/roam/src/utils/syncDgNodesToSupabase.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/main.mdc)

**/*.{ts,tsx}: Use Tailwind CSS for styling where possible
When refactoring inline styles, use tailwind classes
Prefer type over interface in TypeScript
Use explicit return types for functions
Avoid any types when possible
Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use PascalCase for components and types
Use camelCase for variables and functions
Use UPPERCASE for constants
Function names should describe their purpose clearly
Prefer early returns over nested conditionals for better readability

Files:

  • apps/roam/src/utils/internalError.ts
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/syncDgNodesToSupabase.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
apps/roam/**/*.{js,ts,tsx,jsx,json}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Prefer existing dependencies from package.json when working on the Roam Research extension

Files:

  • apps/roam/src/utils/internalError.ts
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/syncDgNodesToSupabase.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
apps/roam/**/*.{ts,tsx,jsx,js,css,scss}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Files:

  • apps/roam/src/utils/internalError.ts
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/syncDgNodesToSupabase.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
apps/roam/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

apps/roam/**/*.{ts,tsx,js,jsx}: Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality
Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Files:

  • apps/roam/src/utils/internalError.ts
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/syncDgNodesToSupabase.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
apps/roam/**

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Implement the Discourse Graph protocol in the Roam Research extension

Files:

  • apps/roam/src/utils/internalError.ts
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/syncDgNodesToSupabase.ts
  • apps/roam/src/components/canvas/Tldraw.tsx
🧠 Learnings (11)
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality

Applied to files:

  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Applied to files:

  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,jsx,js,css,scss} : Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Applied to files:

  • apps/roam/src/components/Export.tsx
📚 Learning: 2025-11-05T21:57:14.909Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 534
File: apps/roam/src/utils/createReifiedBlock.ts:40-48
Timestamp: 2025-11-05T21:57:14.909Z
Learning: In the discourse-graph repository, the function `getPageUidByPageTitle` from `roamjs-components/queries/getPageUidByPageTitle` is a synchronous function that returns a string directly (the page UID or an empty string if not found), not a Promise. It should be called without `await`.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/** : Implement the Discourse Graph protocol in the Roam Research extension

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-06-22T10:40:52.752Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:18-31
Timestamp: 2025-06-22T10:40:52.752Z
Learning: In apps/roam/src/utils/getAllDiscourseNodesSince.ts, the user confirmed that querying for `?title` with `:node/title` and mapping it to the `text` field in the DiscourseGraphContent type is the correct implementation for retrieving discourse node content from Roam Research, despite it appearing to query page titles rather than block text content.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
📚 Learning: 2025-12-07T20:54:19.988Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 559
File: apps/roam/src/utils/findDiscourseNode.ts:37-39
Timestamp: 2025-12-07T20:54:19.988Z
Learning: In apps/roam/src/utils/findDiscourseNode.ts, the function findDiscourseNodeByTitleAndUid accepts both uid and title parameters where uid is primarily used for cache access (as the cache key) while title is used for the actual matching via matchDiscourseNode. This design reflects the pattern where downstream, the uid is mostly used to fetch the title, so the function caches by uid but matches by title.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `type` serves as the unique identifier field, not a type classification field. The interface has no `uid` or `id` field, making `node.type` the correct field to use for UID-related operations.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `node.type` serves as the UID field rather than having a conventional `node.uid` field. This is an unusual naming convention where the type field actually contains the unique identifier.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/canvas/Clipboard.tsx
📚 Learning: 2025-10-18T18:58:16.100Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 504
File: apps/roam/src/utils/syncDgNodesToSupabase.ts:523-531
Timestamp: 2025-10-18T18:58:16.100Z
Learning: In `apps/roam/src/utils/syncDgNodesToSupabase.ts`, partial successes from `upsertNodesToSupabaseAsContent` and `addMissingEmbeddings` (indicated by numeric return values showing the count of successful operations) should NOT trigger backoff. Only complete failures (false) should trigger the exponential backoff mechanism. This design allows the sync process to continue making progress even when some items fail.

Applied to files:

  • apps/roam/src/utils/syncDgNodesToSupabase.ts
📚 Learning: 2025-07-08T14:48:38.048Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 272
File: packages/ui/src/lib/supabase/contextFunctions.ts:50-111
Timestamp: 2025-07-08T14:48:38.048Z
Learning: The Supabase client does not offer transaction support, so idempotent upserts with proper conflict resolution (using onConflict with ignoreDuplicates: false) are the preferred approach for multi-step database operations in packages/ui/src/lib/supabase/contextFunctions.ts. This pattern prevents orphaned records when retrying operations.

Applied to files:

  • apps/roam/src/utils/syncDgNodesToSupabase.ts
🧬 Code graph analysis (1)
apps/roam/src/utils/internalError.ts (1)
apps/roam/src/utils/getVersion.ts (1)
  • getVersionWithDate (9-24)
🔇 Additional comments (14)
apps/roam/src/components/canvas/Tldraw.tsx (1)

89-89: LGTM!

The migration to the centralized internalError utility is clean. The error type follows the new kebab-case convention, and the context includes useful debugging information (title, lastActions).

Also applies to: 511-518

apps/roam/src/components/canvas/useRoamStore.ts (1)

306-312: LGTM!

The error handling in performUpgrade correctly uses the centralized utility with appropriate type and context.

apps/roam/src/components/Export.tsx (2)

312-315: LGTM!

Good improvement switching from let to const for these calculations, enforcing immutability.


471-476: LGTM!

The migration to internalError is consistent. Both error handlers use the same type "export-error", provide a user-facing message, and the export handler includes useful debugging context.

Also applies to: 690-696

apps/roam/src/utils/syncDgNodesToSupabase.ts (1)

63-67: LGTM!

The migration correctly replaces sendErrorEmail with the centralized internalError utility. The error type follows the kebab-case convention, and the toast notification is preserved separately for immediate user feedback.

apps/roam/src/components/CreateRelationDialog.tsx (1)

119-130: LGTM!

The error handling for relation matching edge cases is appropriate, with descriptive messages that include relevant context (types, IDs) for debugging.

apps/roam/src/utils/internalError.ts (3)

33-42: LGTM!

The error normalization logic correctly handles the three cases: string errors, non-Error objects (via JSON serialization with fallback), and actual Error instances. This ensures posthog.captureException always receives a proper Error object.


22-23: Remove redundant posthog.identify() call from error handler.

The user is already identified at app startup in index.ts. Calling posthog.identify(username) on every error is redundant and violates PostHog best practices, which recommend identifying only during identity transitions (login, signup), not on every event. Delete the identify call and let posthog.captureException() use the existing session identity.


43-43: No changes needed. The posthog.captureException(error, context) call uses the correct API signature for PostHog JavaScript SDK v1.261.7, with proper typing.

apps/roam/src/components/canvas/Clipboard.tsx (5)

60-60: LGTM!

The import statement is clean and follows the existing import conventions in the file.


143-151: LGTM!

The early return pattern is correct here since the clipboard cannot function without a user UID. Setting isInitialized to true before returning ensures the component doesn't remain in an initializing state indefinitely.


190-195: LGTM!

The error handling follows the same pattern as the initialization error. The context information (clipboardBlockUid and pageCount) will be helpful for debugging state persistence issues.


434-439: LGTM!

Good error handling with appropriate fallback behavior. Setting discourseNodes to an empty array ensures the component gracefully degrades when discourse nodes cannot be fetched.


594-598: LGTM!

Good defensive programming. Creating a proper Error object with a descriptive message and returning early prevents attempting to create a shape with an invalid node type.

@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🧹 Nitpick comments (1)
apps/roam/src/components/CreateRelationDialog.tsx (1)

25-26: Ensure internalError supports string errors; consider adding structured context

If internalError expects an Error, these calls currently lose stack traces by passing a string (Line 95-99, 118-122, 126-130, 276-279). Consider:

 internalError({
   type: "create-relation-error",
-  error: "Create Relation dialog: Could not identify node downstream",
+  error: new Error("Create Relation dialog: Could not identify node downstream"),
+  context: {
+    selectedRelationName,
+    sourceNodeUid,
+    selectedTargetUid: targetUid,
+    selectedTargetTitle: targetTitle,
+  },
 });

Also applies to: 95-99, 118-122, 126-130, 276-279

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e47ec6 and f39e35c.

📒 Files selected for processing (7)
  • apps/roam/src/components/CreateRelationDialog.tsx (4 hunks)
  • apps/roam/src/components/Export.tsx (5 hunks)
  • apps/roam/src/components/canvas/Clipboard.tsx (7 hunks)
  • apps/roam/src/components/canvas/Tldraw.tsx (2 hunks)
  • apps/roam/src/components/canvas/useRoamStore.ts (5 hunks)
  • apps/roam/src/utils/internalError.ts (1 hunks)
  • apps/roam/src/utils/syncDgNodesToSupabase.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/roam/src/components/canvas/Clipboard.tsx
  • apps/roam/src/utils/syncDgNodesToSupabase.ts
  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/utils/internalError.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/main.mdc)

**/*.{ts,tsx}: Use Tailwind CSS for styling where possible
When refactoring inline styles, use tailwind classes
Prefer type over interface in TypeScript
Use explicit return types for functions
Avoid any types when possible
Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use PascalCase for components and types
Use camelCase for variables and functions
Use UPPERCASE for constants
Function names should describe their purpose clearly
Prefer early returns over nested conditionals for better readability

Files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/Tldraw.tsx
apps/roam/**/*.{js,ts,tsx,jsx,json}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Prefer existing dependencies from package.json when working on the Roam Research extension

Files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/Tldraw.tsx
apps/roam/**/*.{ts,tsx,jsx,js,css,scss}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/Tldraw.tsx
apps/roam/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

apps/roam/**/*.{ts,tsx,js,jsx}: Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality
Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/Tldraw.tsx
apps/roam/**

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Implement the Discourse Graph protocol in the Roam Research extension

Files:

  • apps/roam/src/components/CreateRelationDialog.tsx
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/Tldraw.tsx
🧠 Learnings (9)
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-11-05T21:57:14.909Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 534
File: apps/roam/src/utils/createReifiedBlock.ts:40-48
Timestamp: 2025-11-05T21:57:14.909Z
Learning: In the discourse-graph repository, the function `getPageUidByPageTitle` from `roamjs-components/queries/getPageUidByPageTitle` is a synchronous function that returns a string directly (the page UID or an empty string if not found), not a Promise. It should be called without `await`.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/** : Implement the Discourse Graph protocol in the Roam Research extension

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-06-22T10:40:52.752Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:18-31
Timestamp: 2025-06-22T10:40:52.752Z
Learning: In apps/roam/src/utils/getAllDiscourseNodesSince.ts, the user confirmed that querying for `?title` with `:node/title` and mapping it to the `text` field in the DiscourseGraphContent type is the correct implementation for retrieving discourse node content from Roam Research, despite it appearing to query page titles rather than block text content.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-12-07T20:54:19.988Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 559
File: apps/roam/src/utils/findDiscourseNode.ts:37-39
Timestamp: 2025-12-07T20:54:19.988Z
Learning: In apps/roam/src/utils/findDiscourseNode.ts, the function findDiscourseNodeByTitleAndUid accepts both uid and title parameters where uid is primarily used for cache access (as the cache key) while title is used for the actual matching via matchDiscourseNode. This design reflects the pattern where downstream, the uid is mostly used to fetch the title, so the function caches by uid but matches by title.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `type` serves as the unique identifier field, not a type classification field. The interface has no `uid` or `id` field, making `node.type` the correct field to use for UID-related operations.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `node.type` serves as the UID field rather than having a conventional `node.uid` field. This is an unusual naming convention where the type field actually contains the unique identifier.

Applied to files:

  • apps/roam/src/components/CreateRelationDialog.tsx
📚 Learning: 2025-06-19T19:43:43.380Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 226
File: apps/roam/src/components/settings/HomePersonalSettings.tsx:123-149
Timestamp: 2025-06-19T19:43:43.380Z
Learning: The "Fetch Embeddings for nodes" button in HomePersonalSettings.tsx is for testing purposes only, so it doesn't require production-level error handling or user feedback improvements.

Applied to files:

  • apps/roam/src/components/Export.tsx
🔇 Additional comments (2)
apps/roam/src/components/Export.tsx (1)

225-226: Const-ification looks good

Making props and the bounds intermediates const reduces accidental reassignment risk and reads cleaner.

Also applies to: 311-316

apps/roam/src/components/canvas/Tldraw.tsx (1)

502-533: Remove incorrect dependency suggestion; title capture is safe

The tldraw:error listener correctly uses an empty dependency array. The component is instantiated fresh for each distinct canvas title, so title will not stale. Adding title to dependencies would unnecessarily re-register the event listener.

Regarding lastActionsRef.current: it's already capped at 5 items by design (lines showing if (lastActionsRef.current.length > 5) lastActionsRef.current.shift()), making the payload reasonable. This pattern is consistent with other context passed to internalError (e.g., snapshot data in useRoamStore.ts). PostHog serializes these objects without issue, so no sanitization is required.

Comment on lines 690 to 708
internalError({
error: e as Error,
type: "export-error",
userMessage:
"Looks like there was an error. The team has been notified.",
intent: "danger",
});
sendErrorEmail({
error,
type: "Export Dialog Failed",
context: { activeExportType, filename, results },
}).catch(() => {});
});
setDialogOpen(true);
setError((e as Error).message);
} finally {
Copy link
Contributor

@coderabbitai coderabbitai bot Dec 12, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t send full results to telemetry; don’t surface raw exception messages to users

  • context: { ..., results } (Line 695) can leak user data into PostHog and can be huge.
  • setError((e as Error).message) (Line 698) may expose sensitive/internal details in the dialog.

Suggested diff:

 internalError({
   error: e as Error,
   type: "export-error",
   userMessage:
     "Looks like there was an error. The team has been notified.",
-  context: { activeExportType, filename, results },
+  context: {
+    activeExportType,
+    filename,
+    resultsCount: Array.isArray(results) ? results.length : undefined,
+    // optionally: sample a few UIDs only, if needed for debugging
+    sampleUids: Array.isArray(results) ? results.slice(0, 10).map((r) => r.uid) : undefined,
+  },
 });
 setDialogOpen(true);
-setError((e as Error).message);
+setError("Export failed. Please try again.");
🤖 Prompt for AI Agents
In apps/roam/src/components/Export.tsx around lines 690 to 699, the telemetry
call currently includes full results and the UI exposes the raw exception
message; remove results from the telemetry context (replace with non-sensitive
metadata such as resultCount, exportType, filename or boolean flags) and keep
the actual Error object in internalError for debugging, and change setError to a
generic user-facing message (e.g., "Looks like there was an error. The team has
been notified.") so internal exception text is not shown to users.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch on fullResults. setError is for display, should not leak anything.

Copy link
Contributor

Choose a reason for hiding this comment

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

@maparent Thank you for confirming! I'm glad we're aligned on both points:

  1. Telemetry context: Replacing results with safer metadata like resultsCount and optionally a small sampleUids array will keep debugging useful while protecting user data.
  2. Error display: Using a generic message in setError() (while still passing the full Error to internalError for internal logging) prevents leaking implementation details to users.

Feel free to ping me if you'd like a second look once you've updated the code! 🐰

@maparent
Copy link
Collaborator Author

@CodeRabbit yes internalError does the string-to-error conversion internally.

@maparent maparent marked this pull request as ready for review December 13, 2025 00:42
@maparent maparent requested a review from mdroidian December 13, 2025 00:42
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 13, 2025

Tip

For best results, initiate chat on the files or code changes.

@maparent, thank you for confirming! That's a helpful design decision – having internalError handle the string-to-error conversion internally means callers can pass error messages as strings directly without worrying about wrapping them in Error objects first. I've noted this for future reviews.


✏️ Learnings added
Learnt from: maparent
URL: https://github.com/DiscourseGraphs/discourse-graph/pull/608

Timestamp: 2025-12-13T00:42:41.510Z
Learning: The `internalError` utility in apps/roam/src/utils/internalError.ts handles string-to-error conversion internally. Callers can pass strings directly as the error parameter without needing to convert them to Error objects first.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-08-30T17:03:26.927Z
Learning: For maparent: Prefers to handle retries downstream in Vercel functions rather than at the source level, following separation of concerns principle.

Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

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

Generally looks good.

Just the one code request: keep sendErrorEmail in place, I don't want to remove that.

Also, could you please record a loom video demonstrating this new functionality? Could you also include (either in the loom video or with text+screenshot) some information on where this can be found in posthog, as well as what it looks like/features it enables/etc.

Also note: could we try to keep the PR names in sync with the linear task names please? They are generally more informative and when the PR is a different name it can be harder to locate if you are going from one platform to the other. Thanks.

error = new Error(typeof error);
}
}
posthog.captureException(error, context);
Copy link
Contributor

Choose a reason for hiding this comment

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

also add sendErrorEmail so we continue to get the same error emails.

Copy link
Collaborator Author

Added back sendErrorEmail as an option. I could do a loom video, but honestly nothing much to show; there is no ux for sending an error yet. Should I repurpose the send Email button in the admin panel, esp. now that it does send an email?

But what you do need indeed is where to look for errors:

https://us.posthog.com/project/113823/error_tracking

Now… there are now more errors there than I expected; it seems that enabling error tracking enabled autocapture. I disabled that now, and the error tracking panel still shows.

Two more things need to be added:

  1. Posthog complains about an outdated sdk; I'll make a separate update PR
  2. In production, we should upload the JS code maps, so the stack traces are more legible. That has to be put in the build process. I think that is a separate task, and this code is still usable before that.

@maparent maparent requested a review from mdroidian December 14, 2025 19:12
Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

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

Now… there are now more errors there than I expected; it seems that enabling error tracking enabled autocapture. I disabled that now, and the error tracking panel still shows.

"... and the error tracking panel still shows."
What does the error tracking panel still show? Does it still show all of the autocaptured errors? We need to confirm that we can get only the errors we intentional report before merging this.

This is a good example of what a loom video would help catch before PR review.

Copy link
Collaborator Author

Rephrasing: The error tracking panel (as given by the URL) would be not only empty, but would not even show a empty table for errors; only a "please activate autocapture". I did activate, thinking it needed to also be activated in code, but the activation was somehow in the shared state? Anyhow, deactivated now, and the table with past error still shows, and I did not get back to the "Please activate" empty page.

Copy link
Collaborator Author

And since I (fortunately) cannot go back to the previous un-initialized state, I could not make a very useful loom video here.

@maparent maparent force-pushed the eng-1135-replacing-sendmail-with-explicit-posthog-errors branch from 7c78589 to abc3b18 Compare December 14, 2025 23:30
@maparent maparent requested a review from mdroidian December 14, 2025 23:52
Copy link
Contributor

Can you confirm that we are only getting the errors we intentionally report?

Copy link
Collaborator Author

Hmm… actually, a few came through after I cut off the autocapture setting, so I'm puzzled. (Fewer than before though?) Some of them come from the website, looking into that, but not all of them. Doing some improvement on posthog setup while I'm there.

Copy link
Collaborator Author

Ok. I am looking at the errors that leaked through between my turning off autocapture on the server and now, and they come from other instances. I suspect that some of us started roam during those hours when autocapture was on, the posthog init caught that, and those roam instances will keep that setting until reloaded. Anyhow it started through action on the posthog website, and has nothing to do with the code here, which was not checked in. So I say there is no reason not to check this in.
I did push a few more changes: the adminPanel send email button now uses internalError; I moved some event parameters from the internalError function to posthog initialization.

@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 15, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@maparent
Copy link
Collaborator Author

@maparent maparent force-pushed the eng-1135-replacing-sendmail-with-explicit-posthog-errors branch from 67258a0 to 1da8082 Compare December 15, 2025 19:12
Copy link
Collaborator Author

(btw I was wrong about there being website events; they are in a separate project, as appropriate.)

@maparent maparent force-pushed the eng-1135-replacing-sendmail-with-explicit-posthog-errors branch from e6760cc to 5505b71 Compare December 18, 2025 15:30
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.

3 participants