Skip to content

Commit 80dbf57

Browse files
committed
fix(workflow): stop the editor panel crashing the whole workflow route
Derive the webhook URL only when a sub-block actually displays one, and report boundary errors to PostHog so the next crash arrives with a stack.
1 parent b96c053 commit 80dbf57

2 files changed

Lines changed: 49 additions & 2 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { Component, type ReactNode, useEffect } from 'react'
3+
import { Component, type ErrorInfo, type ReactNode, useEffect } from 'react'
44
import { Button } from '@sim/emcn'
55
import { RefreshCw } from '@sim/emcn/icons'
66
import { createLogger } from '@sim/logger'
@@ -12,6 +12,36 @@ import { readCollapsedCookie } from '@/stores/sidebar/store'
1212

1313
const logger = createLogger('ErrorBoundary')
1414

15+
/**
16+
* Reports a boundary error to PostHog.
17+
*
18+
* Nothing else in the app ships client exceptions anywhere, so a crash on this
19+
* route survives only in the console of whoever hit it — which is why the same
20+
* "Something went wrong" report has had to be diagnosed from screenshots. The
21+
* env snapshot travels with the event because the failures seen so far read an
22+
* empty `NEXT_PUBLIC_APP_URL`, and whether `window.__ENV` was populated at all
23+
* separates a missing deployment value from a document that never ran the
24+
* assignment.
25+
*
26+
* `posthog-js` is imported lazily so the editor route keeps the code-splitting
27+
* the provider sets up, and only pays for the import on the error path.
28+
*/
29+
function reportBoundaryError(error: Error, context: Record<string, unknown>): void {
30+
if (typeof window === 'undefined') return
31+
32+
void import('posthog-js')
33+
.then(({ default: posthog }) => {
34+
if (!posthog.__loaded) return
35+
posthog.captureException(error, {
36+
...context,
37+
pathname: window.location.pathname,
38+
public_env_present: window.__ENV !== undefined,
39+
app_url_present: Boolean(window.__ENV?.NEXT_PUBLIC_APP_URL),
40+
})
41+
})
42+
.catch(() => {})
43+
}
44+
1545
/**
1646
* Shared Error UI Component
1747
*/
@@ -90,6 +120,11 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
90120
return { hasError: true, error }
91121
}
92122

123+
public componentDidCatch(error: Error, info: ErrorInfo): void {
124+
logger.error('Workflow boundary error:', { error, componentStack: info.componentStack })
125+
reportBoundaryError(error, { component_stack: info.componentStack })
126+
}
127+
93128
public render() {
94129
if (this.state.hasError) {
95130
return this.props.fallback || <ErrorUI />
@@ -111,6 +146,7 @@ interface NextErrorProps {
111146
export function NextError({ error, reset }: NextErrorProps) {
112147
useEffect(() => {
113148
logger.error('Workflow error:', { error })
149+
reportBoundaryError(error, { digest: error.digest })
114150
}, [error])
115151

116152
return <ErrorUI onReset={reset} />

apps/sim/hooks/use-webhook-management.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,24 @@ export function useWebhookManagement({
100100
useCallback((state) => state.getValue(blockId, 'triggerPath') as string | null, [blockId])
101101
)
102102

103+
/**
104+
* Derived only when the caller actually renders the URL. `getBaseUrl()` throws
105+
* when `NEXT_PUBLIC_APP_URL` is unset, and `sub-block.tsx` mounts this hook for
106+
* every sub-block in the editor panel — deriving the URL unconditionally turns
107+
* a missing deployment value into a render throw for fields that never display
108+
* one, taking down the whole editor instead of the single webhook field.
109+
* Consumers already gate their reads on `useWebhookUrl`.
110+
*/
103111
const webhookUrl = useMemo(() => {
112+
if (!useWebhookUrl) {
113+
return ''
114+
}
104115
const baseUrl = getBaseUrl()
105116
if (!webhookPath) {
106117
return `${baseUrl}/api/webhooks/trigger/${blockId}`
107118
}
108119
return `${baseUrl}/api/webhooks/trigger/${webhookPath}`
109-
}, [webhookPath, blockId])
120+
}, [useWebhookUrl, webhookPath, blockId])
110121

111122
useEffect(() => {
112123
if (triggerId && !isPreview) {

0 commit comments

Comments
 (0)