Skip to content

#26399#26909

Closed
Rohit7241 wants to merge 2 commits intoTryGhost:mainfrom
Rohit7241:fix-safe-json-parse-portal
Closed

#26399#26909
Rohit7241 wants to merge 2 commits intoTryGhost:mainfrom
Rohit7241:fix-safe-json-parse-portal

Conversation

@Rohit7241
Copy link

@Rohit7241 Rohit7241 commented Mar 22, 2026

🐛 Fixed portal URL hash parsing to prevent crash

closes #26399

The previous implementation of parsing URL hash parameters could throw errors if the hash was malformed or missing. This change introduces a safe JSON parse utility that ensures invalid or empty hashes do not crash the portal. This improves stability and prevents unexpected runtime errors for users navigating with unusual URLs.


Note

Medium Risk
Changes how Portal interprets URL hash/query parameters by making JSON parsing fault-tolerant and swallowing hashchange update errors, which could alter preview/link behavior when parameters are malformed or unexpectedly formatted.

Overview
Prevents Portal from crashing on malformed or missing URL hash/query parameters by introducing a safeJSONParse helper and using it in preview/query parsing instead of JSON.parse.

Also wraps updateStateForPreviewLinks in a try/catch so hashchange-driven state updates fail gracefully (logging a warning) rather than taking down the app.

Written by Cursor Bugbot for commit ed640ae. This will update automatically on new commits. Configure here.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 22, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 27f46de2-a9f2-4bf2-9492-65878e2d12c6

📥 Commits

Reviewing files that changed from the base of the PR and between eba6d22 and ed640ae.

📒 Files selected for processing (1)
  • apps/portal/src/app.js

Walkthrough

Added a safeJSONParse(value, fallback = null) helper to catch JSON.parse errors and return a fallback while logging a console warning. Replaced direct JSON.parse(value) calls with safeJSONParse(value) for preview-mode parameters including button, name, signupCheckboxRequired, disableBackground, transistorPortalSettings, and plan-gating flags (isFree, isMonthly, isYearly). Wrapped updateStateForPreviewLinks() in a try/catch so failures during preview-data fetching or state updates are logged and abort the update instead of throwing.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title '#26399' references only the issue number without describing the actual change, making it unclear what the PR accomplishes. Consider using a descriptive title like 'Add safe JSON parsing for portal URL parameters to prevent crashes' to clarify the main change.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the issue being fixed, the solution implemented, and links to the related issue, providing good context for the changes.
Linked Issues check ✅ Passed The PR successfully addresses all objectives from issue #26399: introduces safeJSONParse helper, replaces JSON.parse calls for 9 parameters, and wraps updateStateForPreviewLinks in try/catch for hashchange protection.
Out of Scope Changes check ✅ Passed All changes are focused on fixing malformed URL hash parsing in the Portal widget, directly addressing the issue requirements without unrelated modifications.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

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/portal/src/app.js (1)

394-439: Use typed fallbacks to keep preview state shape stable.

safeJSONParse(value) defaults to null for all fields. For boolean/string/object fields, explicit fallbacks (false, '', {}) reduce downstream null-guard burden and keep state types predictable.

♻️ Suggested adjustment
-                data.site.portal_button = safeJSONParse(value);
+                data.site.portal_button = safeJSONParse(value, '');

-                data.site.portal_name = safeJSONParse(value);
+                data.site.portal_name = safeJSONParse(value, '');

-            } else if (key === 'isFree' && safeJSONParse(value)) {
+            } else if (key === 'isFree' && safeJSONParse(value, false)) {
                 allowedPlans.push('free');
-            } else if (key === 'isMonthly' && safeJSONParse(value)) {
+            } else if (key === 'isMonthly' && safeJSONParse(value, false)) {
                 allowedPlans.push('monthly');
-            } else if (key === 'isYearly' && safeJSONParse(value)) {
+            } else if (key === 'isYearly' && safeJSONParse(value, false)) {
                 allowedPlans.push('yearly');

-                data.site.portal_signup_checkbox_required = safeJSONParse(value);
+                data.site.portal_signup_checkbox_required = safeJSONParse(value, false);

-                data.site.disableBackground = safeJSONParse(value);
+                data.site.disableBackground = safeJSONParse(value, false);

-                data.site.transistor_portal_settings = safeJSONParse(value);
+                data.site.transistor_portal_settings = safeJSONParse(value, {});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/portal/src/app.js` around lines 394 - 439, Several assignments use
safeJSONParse(value) which returns null by default and can make the preview
state shape nullable; update each field assignment (e.g.,
data.site.portal_button, data.site.portal_name,
data.site.portal_signup_checkbox_required, data.site.disableBackground,
data.site.transistor_portal_settings, and any other safeJSONParse uses) to
provide typed fallbacks instead of null — use '' for strings, false for
booleans, {} for objects/records and [] for arrays as appropriate so the preview
state remains stable and downstream code doesn’t need extra null guards.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/portal/src/app.js`:
- Around line 29-37: safeJSONParse currently calls itself recursively causing a
stack overflow; replace the recursive call with a direct JSON.parse(value)
invocation and keep the existing try/catch/fallback behavior so function
safeJSONParse(value, fallback = null) attempts JSON.parse(value) and on any
exception logs the warning via console.warn and returns fallback.

---

Nitpick comments:
In `@apps/portal/src/app.js`:
- Around line 394-439: Several assignments use safeJSONParse(value) which
returns null by default and can make the preview state shape nullable; update
each field assignment (e.g., data.site.portal_button, data.site.portal_name,
data.site.portal_signup_checkbox_required, data.site.disableBackground,
data.site.transistor_portal_settings, and any other safeJSONParse uses) to
provide typed fallbacks instead of null — use '' for strings, false for
booleans, {} for objects/records and [] for arrays as appropriate so the preview
state remains stable and downstream code doesn’t need extra null guards.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3d82627e-355f-4c65-8567-e974dd1549ff

📥 Commits

Reviewing files that changed from the base of the PR and between 248fe42 and eba6d22.

📒 Files selected for processing (1)
  • apps/portal/src/app.js

Comment on lines +29 to +37
function safeJSONParse(value, fallback = null) {
try {
return safeJSONParse(value);
} catch (e) {
/* eslint-disable no-console */
console.warn('[Portal] Invalid JSON in URL parameter:', e.message);
return fallback;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix recursive call in safeJSONParse (stack overflow on every invocation).

Line 31 calls safeJSONParse from inside safeJSONParse, so each parse recurses until a RangeError occurs and then falls back. This is a critical correctness/performance issue. It should call JSON.parse(value) directly.

🐛 Proposed fix
 function safeJSONParse(value, fallback = null) {
     try {
-        return safeJSONParse(value);
+        return JSON.parse(value);
     } catch (e) {
         /* eslint-disable no-console */
         console.warn('[Portal] Invalid JSON in URL parameter:', e.message);
         return fallback;
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function safeJSONParse(value, fallback = null) {
try {
return safeJSONParse(value);
} catch (e) {
/* eslint-disable no-console */
console.warn('[Portal] Invalid JSON in URL parameter:', e.message);
return fallback;
}
}
function safeJSONParse(value, fallback = null) {
try {
return JSON.parse(value);
} catch (e) {
/* eslint-disable no-console */
console.warn('[Portal] Invalid JSON in URL parameter:', e.message);
return fallback;
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/portal/src/app.js` around lines 29 - 37, safeJSONParse currently calls
itself recursively causing a stack overflow; replace the recursive call with a
direct JSON.parse(value) invocation and keep the existing try/catch/fallback
behavior so function safeJSONParse(value, fallback = null) attempts
JSON.parse(value) and on any exception logs the warning via console.warn and
returns fallback.

@Rohit7241 Rohit7241 closed this Mar 22, 2026
@Rohit7241 Rohit7241 deleted the fix-safe-json-parse-portal branch March 22, 2026 11:54
@Rohit7241 Rohit7241 restored the fix-safe-json-parse-portal branch March 22, 2026 11:56
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.

Unhandled JSON.parse() exceptions in Portal's fetchQueryStrData() crash widget on malformed preview URLs

1 participant