Skip to content

Conversation

@SuyashJain17
Copy link
Contributor

@SuyashJain17 SuyashJain17 commented Dec 30, 2025

Proposed change

Resolves #3082

This PR prevents a runtime crash caused by invalid theme values being applied as CSS class names during initial render.

next-themes applies the persisted theme value directly to the class attribute. If the stored value contains spaces (for example "Default Theme"), this results in an InvalidCharacterError and the app crashes before rendering.

The fix validates persisted theme values and falls back safely to a CSS-safe default during initialization.

Checklist

  • Required: I read and followed the contributing guidelines
  • Required: I ran make check-test locally and all tests passed
  • I used AI for code, documentation, or tests in this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 30, 2025

Summary by CodeRabbit

  • Bug Fixes
    • Improved theme persistence by automatically sanitizing invalid stored theme values. Theme settings with formatting issues are now corrected on app load, ensuring the theme system functions properly without user intervention.

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

Walkthrough

Added runtime sanitation to the theme provider that removes spaces from persisted localStorage theme values. This prevents invalid CSS class names from crashing the application during initialization when malformed theme values are encountered.

Changes

Cohort / File(s) Summary
Theme value sanitation
frontend/src/wrappers/provider.tsx
Added logic to sanitize persisted theme values by removing spaces before applying them. Updated comment clarification regarding AppInitializer and session handling.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: preventing crashes from invalid theme classes during initialization, which aligns with the primary code change.
Description check ✅ Passed The description comprehensively explains the bug, the proposed solution, and links to the relevant issue, demonstrating clear understanding of the changeset.
Linked Issues check ✅ Passed The PR successfully addresses issue #3082 by validating persisted theme values and removing invalid ones to prevent InvalidCharacterError crashes during initialization.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the theme initialization crash issue; the updated comment is necessary context and no unrelated modifications are present.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d329ce and 0979dca.

📒 Files selected for processing (1)
  • frontend/src/wrappers/provider.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/wrappers/provider.tsx

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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7caf577 and 606cbc0.

📒 Files selected for processing (1)
  • frontend/src/wrappers/provider.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-17T02:42:41.928Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 2288
File: frontend/src/components/ActionButton.tsx:0-0
Timestamp: 2025-09-17T02:42:41.928Z
Learning: In frontend/src/components/ActionButton.tsx, the user Rajgupta36 intentionally changed text-blue-600 to text-[#1D7BD7] to align the text color with the border color (#1D7BD7) for visual consistency, prioritizing design alignment over theme tokens.

Applied to files:

  • frontend/src/wrappers/provider.tsx

@SuyashJain17
Copy link
Contributor Author

Thanks for the feedback. Agreed that forcing the theme breaks ModeToggle.

I’ll update the PR to validate persisted theme values and preserve theme switching instead of forcing a single theme.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 30, 2025
@arkid15r arkid15r marked this pull request as draft December 30, 2025 17:40
Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

Please also fix all sonar wanrings

@SuyashJain17 SuyashJain17 marked this pull request as ready for review December 30, 2025 18:17
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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ddc488 and 8aabaf4.

📒 Files selected for processing (1)
  • frontend/src/wrappers/provider.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-17T02:42:41.928Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 2288
File: frontend/src/components/ActionButton.tsx:0-0
Timestamp: 2025-09-17T02:42:41.928Z
Learning: In frontend/src/components/ActionButton.tsx, the user Rajgupta36 intentionally changed text-blue-600 to text-[#1D7BD7] to align the text color with the border color (#1D7BD7) for visual consistency, prioritizing design alignment over theme tokens.

Applied to files:

  • frontend/src/wrappers/provider.tsx
📚 Learning: 2025-07-13T11:29:25.245Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:59-61
Timestamp: 2025-07-13T11:29:25.245Z
Learning: In Next.js 13+ app router, components with the 'use client' directive run entirely on the client side and don't require window object existence checks or SSR hydration considerations. Direct access to window.location and other browser APIs is safe in client components.

Applied to files:

  • frontend/src/wrappers/provider.tsx
🧬 Code graph analysis (1)
frontend/src/wrappers/provider.tsx (1)
frontend/src/hooks/useDjangoSession.ts (1)
  • useDjangoSession (10-83)
🔇 Additional comments (3)
frontend/src/wrappers/provider.tsx (3)

11-12: LGTM! Clean type-safe theme definition.

The const assertion and derived ValidTheme type provide compile-time safety for theme values throughout the component.


44-49: NextThemesProvider configuration is correct.

The configuration properly restricts allowed themes via themes={VALID_THEMES} and uses a consistent storageKey that matches getValidTheme(). The defaultTheme={theme} provides a validated fallback when no theme is stored or after invalid values are cleaned up.

Note: enableSystem defaults to true in next-themes, so the provider will detect and respect the user's system theme preference when no explicit theme is stored.


38-38: The code pattern is correct and follows next-themes best practices. The React.useState lazy initialization properly calls getValidTheme only once on client mount. While a theoretical hydration difference exists (server returns 'dark' when window is undefined, client might read localStorage), next-themes is specifically designed to handle this scenario: it suppresses theme application during hydration and reconciles the state afterward without warnings.

Additionally, ModeToggle.tsx implements the standard hydration safety pattern with the mounted state check, preventing any issues when reading the current theme. No actual hydration mismatches are evident in the codebase.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 30, 2025
@SuyashJain17
Copy link
Contributor Author

I noticed a low-severity SonarCloud warning suggesting globalThis.window.
I kept typeof window === 'undefined' here as it’s the standard SSR pattern
in Next.js and aligns with the CodeRabbit feedback.

Please let me know if you’d prefer a different approach.

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

I don't think I understand the code and the issues it fixes.
Also have some doubts about specific code parts:

if (stored) {
localStorage.removeItem('__nest_theme__')
}
} catch {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think it's a good idea.

// It ensures the session is synced with Django when the app starts.
// AppInitializer is mounted once. Its job is to call useDjangoSession(),
// which syncs the GitHub access token (stored in the NextAuth session) with the Django session.
const VALID_THEMES = ['dark', 'light'] as const
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't remove existing comments.

// It ensures the session is synced with Django when the app starts.
// AppInitializer is mounted once. Its job is to call useDjangoSession(),
// which syncs the GitHub access token (stored in the NextAuth session) with the Django session.
const VALID_THEMES = ['dark', 'light'] as const
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do you need const twice here?

@arkid15r arkid15r marked this pull request as draft January 1, 2026 20:03
@SuyashJain17 SuyashJain17 marked this pull request as ready for review January 2, 2026 05:19
@SuyashJain17
Copy link
Contributor Author

Thanks for the detailed feedback - that helps.

The issue this PR fixes is a runtime crash caused by next-themes applying a persisted theme value directly as a CSS class during initial render. If the stored value contains spaces (for example "Default Theme"), the browser throws an InvalidCharacterError and the app crashes before rendering.

The cleanup logic only removes the persisted value when it’s invalid (i.e. not one of ['dark', 'light']). This allows next-themes to fall back to a safe default and prevents the crash. Valid user preferences are not touched.

I agree the intent wasn’t clear enough from the code. I’ll:

  • Add an explicit comment explaining the crash scenario and why the cleanup is needed

  • Move the theme validation helpers away from the Django session–related comments

  • Simplify the typing to avoid confusion around const / as const

Please let me know if you’d prefer a different approach (for example sanitizing instead of removing). I’m happy to adjust.

coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 2, 2026
coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 2, 2026
@SuyashJain17
Copy link
Contributor Author

Closing this PR since it contains multiple unrelated changes from an earlier branch.
I’ll open a clean, scoped PR for the assigned issue. Thanks!

@arkid15r
Copy link
Collaborator

arkid15r commented Jan 2, 2026

You should never close a PR unless you're asked to. PR is a "shell" for your code to be reviewed/merged. As an author you can do whatever you need w/ your branch linked to this PR.

@arkid15r arkid15r reopened this Jan 2, 2026
@SuyashJain17
Copy link
Contributor Author

Thanks for clarifying, that makes sense - appreciate it.

I closed the PR earlier because the branch had accumulated multiple unrelated commits from experimentation, and I didn’t want to risk merging unintended changes.

I understand now that the PR can remain open while I clean up the branch history. I’ll rebase this PR onto a clean state and update it accordingly.

@SuyashJain17
Copy link
Contributor Author

Removed the dependency cleanup commit so this PR focuses only on the theme initialization crash fix.

Comment on lines 25 to 34
/**
* next-themes applies the persisted theme value directly as a CSS class
* during initial render.
*
* If the stored value contains spaces (e.g. "Default Theme"), the browser
* throws InvalidCharacterError and the app crashes before rendering.
*
* To prevent this, we validate the persisted value and remove it only
* if it is invalid, allowing next-themes to safely fall back to default.
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

@SuyashJain17 can you provide steps how to replicate this issue you're trying to fix? 👀
Current default theme is set to "dark", so I'm not sure how it's possible to have it set to something like "Default Theme", unless user goes in and manually updates it in local storage.

Is that the scenario you're working with?

Even if so, I believe toggling the theme toggle again - would update the value.
However, even if we'd want to add extra validation, I believe the solution can be much much simpler - like a 1-2 lines change 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the follow-up — adding concrete details from the browser console.

Reproduction (local via Docker)

  1. Start the app using the standard Docker setup:
    docker compose -f docker-compose/local/compose.yaml up --build
  2. Open the frontend at http://localhost:3000
  3. Open the browser Developer Console
  4. Reload the page

Explanation

next-themes applies the persisted theme value directly as a CSS class
during initial render. If the value contains spaces (e.g. "Default Theme"),
the browser throws InvalidCharacterError because class tokens cannot contain
whitespace. This happens before React finishes mounting, causing a crash
before hydration and before the theme toggle can run.

The fix can be minimal: remove the persisted value only when it contains
invalid CSS characters, allowing next-themes to fall back safely.

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

There's also unresolved Sonar issue still - you're required to resolve them all before we review, no matter how high the priority is on them.

coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 4, 2026
@SuyashJain17
Copy link
Contributor Author

Thanks for the review!
SonarCloud is now green (Quality Gate passed).
I’ve simplified the fix to a minimal guard as suggested, and the crash no longer reproduces locally.
Happy to adjust further if needed.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 4, 2026

@arkid15r
Copy link
Collaborator

arkid15r commented Jan 6, 2026

I don't think we'll be merging this.
Please feel free to update the troubleshooting section of https://github.com/OWASP/Nest/blob/main/CONTRIBUTING.md#troubleshooting though

@arkid15r arkid15r closed this Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local dev crash: InvalidCharacterError caused by non-CSS-safe theme value

3 participants