Skip to content

fix: handle invalid webhook jsonPayload without crashing#3019

Open
badja-dev wants to merge 4 commits into
seerr-team:developfrom
badja-dev:fix/webhook-settings-crash-on-invalid-payload
Open

fix: handle invalid webhook jsonPayload without crashing#3019
badja-dev wants to merge 4 commits into
seerr-team:developfrom
badja-dev:fix/webhook-settings-crash-on-invalid-payload

Conversation

@badja-dev
Copy link
Copy Markdown

@badja-dev badja-dev commented May 12, 2026

Description

I noticed an error in my Seerr logs where a webhook notification was failing with "[object Object]" is not valid JSON. When I went to check the webhook settings page to investigate, I was met with an "Oops" crash screen instead.

After digging into the network tab I found the settings page API was returning HTTP 500. The GET /webhook route in notifications.ts calls JSON.parse(Buffer.from(jsonPayload, 'base64')) with no error handling - if the stored payload is empty or malformed (which can happen after a settings migration), it throws an unhandled exception. The frontend only guarded against a loading state with if (!data && !error) and had no handling for the error case, so when the API returned 500, data was undefined and the component crashed on data.enabled.

Changes:

  • Wrapped the JSON.parse call in notifications.ts in a try/catch so the route returns a safe fallback instead of throwing a 500 - Added an error state render in NotificationsWebhook/index.tsx s the page shows a readable message instead of crashing

How Has This Been Tested?

Reproduced on my own Seerr v3.2.0 Docker instance. The settings page crashed consistently before the fix and loaded correctly after. I also ran pnpm build locally and it completed without errors or warnings from the changed files.

Screenshots / Logs (if applicable)

Log error that triggered the investigation:

[error][Notifications]: Error sending webhook notification
{"type":"MEDIA_AUTO_APPROVED","errorMessage":"\"[object Object]\" is not valid JSON"}

Browser console errors on the Oops screen:

TypeError: Cannot read properties of undefined (reading 'enabled')
TypeError: e.match is not a function

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI - I used Claude to help diagnose the issue and identify the affected files. The code changes and this submission are my own.
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • Bug Fixes

    • Webhook settings now handle invalid payloads gracefully, falling back to an empty value instead of throwing on decode/parse errors.
    • Notification settings show a clear error panel when webhook data fails to load; the loading indicator appears only when data is absent.
  • Localization

    • Added localized message for webhook settings load failures.

Review Change Stack

The GET /webhook API route called JSON.parse(Buffer.from(jsonPayload, 'base64'))
with no error handling. If jsonPayload was empty or malformed (e.g. after a
settings migration), the route threw an unhandled exception and returned HTTP 500.

The frontend webhook settings component used `if (!data && !error)` as its only
loading guard. When the API returned 500, `data` was undefined and `error` was
truthy - the component fell through and crashed on `data.enabled`.

Fixes:
- Wrap the JSON.parse call in notifications.ts in a try/catch with a safe fallback
- Add an explicit error state render in NotificationsWebhook/index.tsx
@badja-dev badja-dev requested a review from a team as a code owner May 12, 2026 10:49
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 96dcffb7-b7cc-47c3-a74a-69a814cfcab5

📥 Commits

Reviewing files that changed from the base of the PR and between 8a0a592 and b378014.

📒 Files selected for processing (1)
  • src/i18n/locale/en.json
✅ Files skipped from review due to trivial changes (1)
  • src/i18n/locale/en.json

📝 Walkthrough

Walkthrough

Server GET /webhook now safely decodes/parses webhookSettings.options.jsonPayload inside a try/catch (falls back to empty string). NotificationsWebhook shows a localized red error panel when the SWR fetch errors; loading spinner appears only when data is absent. i18n strings added/updated.

Changes

Webhook settings error handling

Layer / File(s) Summary
Server-side webhook payload parsing robustness
server/routes/settings/notifications.ts
The GET /webhook endpoint wraps webhookSettings.options.jsonPayload decoding and JSON.parse in a try/catch; invalid base64 or JSON now falls back to an empty string instead of throwing.
Client-side webhook error state rendering
src/components/Settings/Notifications/NotificationsWebhook/index.tsx, src/i18n/locale/en.json
NotificationsWebhook returns an early localized red error panel when SWR reports error; the loading spinner shows only when data is missing. Added webhookSettingsLoadError translation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • fallenbagel
  • gauthier-th

Poem

🐇 I nibble bugs where webhooks sleep,
I catch the throws before they leap.
When base64 crumbles in the night,
I return calm, keep logs polite.
A red panel blooms — the app sleeps tight.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and concisely describes the main change: adding error handling to prevent crashes when the webhook jsonPayload is invalid, which aligns with the core issue and fix described in the PR objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Settings/Notifications/NotificationsWebhook/index.tsx`:
- Line 212: Replace the hardcoded string "Failed to load webhook settings.
Please check your configuration and try refreshing." with a localized message:
add a messages object via defineMessages (e.g., const messages =
defineMessages({ loadError: { id: 'notifications.webhook.loadError',
defaultMessage: 'Failed to load webhook settings. Please check your
configuration and try refreshing.' } })) and use
intl.formatMessage(messages.loadError) where the string is currently used
(ensure the component has access to the intl prop via injectIntl or useIntl and
reference the component name NotificationsWebhook or the render function that
contains the message).
- Around line 209-214: The component currently returns an error UI when error is
truthy but later dereferences SWR's data (e.g., data.enabled) without guarding
for the loading state; add a loading guard that checks for !data (or data ===
undefined) before accessing fields used as form initial values in this
NotificationsWebhook component (where data and error come from the SWR hook),
and render a loading placeholder (or return null) until data is available to
prevent runtime crashes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 376964b7-5256-4823-b5f3-10418ef9349d

📥 Commits

Reviewing files that changed from the base of the PR and between dfde4d3 and d0f4ff4.

📒 Files selected for processing (2)
  • server/routes/settings/notifications.ts
  • src/components/Settings/Notifications/NotificationsWebhook/index.tsx

Comment thread src/components/Settings/Notifications/NotificationsWebhook/index.tsx Outdated
badja-dev added 3 commits May 12, 2026 12:09
…ges. purely defensive. try/catc

two files touched, no logic changes, purely defensive. The bakcend change wraps one existing
`JSON.parse` call in a try-catch so the GET `/webook` route returns and empty string fallback
instead of throwing a 500 when the stored payload is malformed. The frontend change adds two missing
guard clauses - one to render an error panel when the API call fails, and one to hold the loading
spinner until `data` is actually available - preventing a crash on `data.enabled` when `data` is
undefined. No new features, no shcema changes, no changes to how payloads are saved or sent
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