Skip to content

fix(webhook): throw webhook errors as 4xxs#4050

Merged
TheodoreSpeaks merged 2 commits intostagingfrom
fix/preprocessing-error
Apr 8, 2026
Merged

fix(webhook): throw webhook errors as 4xxs#4050
TheodoreSpeaks merged 2 commits intostagingfrom
fix/preprocessing-error

Conversation

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator

Summary

We recently cought all preprocessResult errors as 5xxs. These can be caused by workflows deleted, usage limit exceeded, rate limit exceeded, etc which are all user errors. Changed this to correctly throw using status and error passed from preprocessResult

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

  • Manual validation. This is an internal endpoint, and changing from 4xx to 5xx is mostly for metrics and doesn't cause changes in behavior.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 8, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 8, 2026 7:10pm

Request Review

@cursor
Copy link
Copy Markdown

cursor bot commented Apr 8, 2026

PR Summary

Low Risk
Low risk: change only affects error mapping/logging for polled webhook preprocessing failures, but could alter returned status codes/messages and thus metrics/alerting for polling providers.

Overview
Polled webhook processing now propagates preprocessing failures as their original HTTP status and error message instead of always returning a generic 500.

processPolledWebhookEvent extracts status and JSON { error } from the checkWebhookPreprocessing NextResponse, logs the details, and returns them to polling callers.

Reviewed by Cursor Bugbot for commit c82de96. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 8, 2026

Greptile Summary

This PR fixes checkWebhookPreprocessing in processor.ts so that errors returned by preprocessExecution propagate their own statusCode (404 for deleted workflows, 403 for undeployed, 429 for rate limits, etc.) rather than being hardcoded to 500. The catch block for genuine unexpected exceptions correctly retains a 500 response.

Confidence Score: 4/5

Safe to merge — the fix correctly propagates preprocessing status codes, the change is minimal and well-scoped, and the catch block still guards against unexpected exceptions.

The logic change is straightforward and correct. The only minor concern is a non-null assertion on an optional TypeScript field that is safe today but could be fragile if the preprocessExecution interface evolves.

apps/sim/lib/webhooks/processor.ts line 453 — non-null assertion on optional error field.

Vulnerabilities

No security concerns identified. Propagating correct HTTP status codes for client errors does not introduce any injection, auth bypass, or data exposure risks.

Important Files Changed

Filename Overview
apps/sim/lib/webhooks/processor.ts Fixes checkWebhookPreprocessing to propagate the actual error.statusCode from preprocessExecution instead of hardcoding 500, correctly surfacing 4xx errors for user-caused failures (deleted workflows, rate limits, etc.); uses a non-null assertion on an optional field.

Sequence Diagram

sequenceDiagram
    participant WH as Webhook Route
    participant CP as checkWebhookPreprocessing
    participant PE as preprocessExecution
    participant FPE as formatProviderErrorResponse

    WH->>CP: checkWebhookPreprocessing(workflow, webhook, requestId)
    CP->>PE: preprocessExecution({workflowId, userId, ...})
    alt success === false (user error: deleted, rate-limit, etc.)
        PE-->>CP: {success: false, error: {message, statusCode: 4xx|5xx}}
        CP->>FPE: formatProviderErrorResponse(webhook, error.message, error.statusCode)
        FPE-->>CP: NextResponse (correct 4xx or 5xx)
        CP-->>WH: {error: NextResponse}
    else success === true
        PE-->>CP: {success: true, actorUserId, ...}
        CP-->>WH: {error: null, actorUserId, executionId, correlation}
    else unexpected exception thrown
        PE-->>CP: throws
        CP->>FPE: formatProviderErrorResponse(webhook, 'Internal error during preprocessing', 500)
        FPE-->>CP: NextResponse (500)
        CP-->>WH: {error: NextResponse (500)}
    end
Loading

Comments Outside Diff (1)

  1. apps/sim/lib/webhooks/processor.ts, line 453 (link)

    P2 Non-null assertion on optional field

    preprocessResult.error! silences TypeScript's complaint, but the PreprocessExecutionResult interface declares error as optional (error?). While the current implementation of preprocessExecution always supplies an error object when success === false, any future path that returns {success: false} without error will throw at runtime. A defensive fallback is safer.

Reviews (1): Last reviewed commit: "fix(webhook): throw webhook errors as 4x..." | Re-trigger Greptile

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ce3859d. Configure here.

@TheodoreSpeaks TheodoreSpeaks merged commit 621aa65 into staging Apr 8, 2026
12 checks passed
TheodoreSpeaks added a commit that referenced this pull request Apr 8, 2026
* fix(webhook): throw webhook errors as 4xxs

* Fix shadowing body var

---------

Co-authored-by: Theodore Li <theo@sim.ai>
TheodoreSpeaks added a commit that referenced this pull request Apr 8, 2026
* fix(billing): skip billing on streamed workflows with byok

* Simplify logic

* Address comments, skip tokenization billing fallback

* Fix tool usage billing for streamed outputs

* fix(webhook): throw webhook errors as 4xxs (#4050)

* fix(webhook): throw webhook errors as 4xxs

* Fix shadowing body var

---------

Co-authored-by: Theodore Li <theo@sim.ai>

* feat(enterprise): cloud whitelabeling for enterprise orgs (#4047)

* feat(enterprise): cloud whitelabeling for enterprise orgs

* fix(enterprise): scope enterprise plan check to target org in whitelabel PUT

* fix(enterprise): use isOrganizationOnEnterprisePlan for org-scoped enterprise check

* fix(enterprise): allow clearing whitelabel fields and guard against empty update result

* fix(enterprise): remove webp from logo accept attribute to match upload hook validation

* improvement(billing): use isBillingEnabled instead of isProd for plan gate bypasses

* fix(enterprise): show whitelabeling nav item when billing is enabled on non-hosted environments

* fix(enterprise): accept relative paths for logoUrl since upload API returns /api/files/serve/ paths

* fix(whitelabeling): prevent logo flash on refresh by hiding logo while branding loads

* fix(whitelabeling): wire hover color through CSS token on tertiary buttons

* fix(whitelabeling): show sim logo by default, only replace when org logo loads

* fix(whitelabeling): cache org logo url in localstorage to eliminate flash on repeat visits

* feat(whitelabeling): add wordmark support with drag/drop upload

* updated turbo

* fix(whitelabeling): defer localstorage read to effect to prevent hydration mismatch

* fix(whitelabeling): use layout effect for cache read to eliminate logo flash before paint

* fix(whitelabeling): cache theme css to eliminate color flash before org settings resolve

* fix(whitelabeling): deduplicate HEX_COLOR_REGEX into lib/branding and remove mutation from useCallback deps

* fix(whitelabeling): use cookie-based SSR cache to eliminate brand flash on all page loads

* fix(whitelabeling): use !orgSettings condition to fix SSR brand cache injection

React Query returns isLoading: false with data: undefined during SSR, so the
previous brandingLoading condition was always false on the server — initialCache
was never injected into brandConfig. Changing to !orgSettings correctly applies
the cookie cache both during SSR and while the client-side query loads, eliminating
the logo flash on hard refresh.

* fix(editor): stop highlighting start.input as blue when block is not connected to starter (#4054)

* fix: merge subblock values in auto-layout to prevent losing router context (#4055)

Auto-layout was reading from getWorkflowState() without merging subblock
store values, then persisting stale subblock data to the database. This
caused runtime-edited values (e.g. router_v2 context) to be overwritten
with their initial/empty values whenever auto-layout was triggered.

* fix(whitelabeling): eliminate logo flash by fetching org settings server-side (#4057)

* fix(whitelabeling): eliminate logo flash by fetching org settings server-side

* improvement(whitelabeling): add SVG support for logo and wordmark uploads

* skelly in workspace header

* remove dead code

* fix(whitelabeling): hydration error, SVG support, skeleton shimmer, dead code removal

* fix(whitelabeling): blob preview dep cycle and missing color fallback

* fix(whitelabeling): use brand-accent as color fallback when workspace color is undefined

* chore(whitelabeling): inline hasOrgBrand

---------

Co-authored-by: Theodore Li <theo@sim.ai>
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