Skip to content

fix: handle errors in css.__withStyles getDynamicPatch#5

Merged
hyochan merged 3 commits intomainfrom
fix/css-withstyles-error-handling
Mar 13, 2026
Merged

fix: handle errors in css.__withStyles getDynamicPatch#5
hyochan merged 3 commits intomainfrom
fix/css-withstyles-error-handling

Conversation

@hyochan
Copy link
Member

@hyochan hyochan commented Mar 13, 2026

Summary

  • Add try-catch around getDynamicPatch({}) in css.__withStyles to prevent crashes when theme-dependent functions are called with empty props
  • Add try-catch around JSON.stringify(dynamicPatch) to handle circular references (e.g., DOM elements on web)
  • Skip caching for non-serializable patches instead of crashing

Test plan

  • Added test: should not crash when getDynamicPatch throws (theme-dependent css``)
  • Added test: should not crash when JSON.stringify encounters circular references
  • Verify web rendering works without circular reference errors

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Dynamic CSS patching now handles errors and non-serializable values without crashing.
  • Tests

    • Added tests covering serialization edge cases and error scenarios for dynamic CSS patches.
  • Documentation

    • Added developer workflow guides for committing changes and reviewing PRs, including commit/PR templates and step-by-step checklists.

Add try-catch around getDynamicPatch({}) and JSON.stringify in
__withStyles to prevent crashes when:
- getDynamicPatch contains theme-dependent functions (calling with {} has no theme)
- Dynamic patch objects contain circular references (e.g., DOM elements on web)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the robustness of the kstyled library by introducing comprehensive error handling within the css.__withStyles function. It specifically addresses potential crashes that could arise from getDynamicPatch when theme properties are undefined or from JSON.stringify when encountering circular references in dynamic style objects. These changes ensure that the styling system remains stable and continues to render, even when faced with unexpected or non-serializable dynamic style configurations, improving the overall resilience of the component styling.

Highlights

  • Error Handling for getDynamicPatch: Added try-catch logic around getDynamicPatch({}) within css.__withStyles to prevent crashes when theme-dependent functions are called with empty props, which can occur when the theme is not yet available.
  • Circular Reference Handling: Implemented a try-catch block around JSON.stringify(dynamicPatch) to gracefully handle cases where dynamic patches contain circular references (e.g., DOM elements on the web), preventing application crashes.
  • Dynamic Patch Caching: Modified the caching mechanism to skip caching for dynamic patches that are non-serializable (i.e., those that cause JSON.stringify to fail), ensuring stability without crashing.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • packages/kstyled/src/tests/runtime.test.tsx
    • Added a test case to ensure css.__withStyles does not crash when getDynamicPatch throws an error due to missing theme properties.
    • Added a test case to verify that css.__withStyles gracefully handles circular references during JSON.stringify without crashing.
  • packages/kstyled/src/css.tsx
    • Implemented a try-catch block around the getDynamicPatch({}) call to prevent crashes from theme-dependent functions.
    • Introduced a try-catch block around JSON.stringify(dynamicPatch) to manage non-serializable values, such as circular references, by falling back to an empty hash.
    • Updated the caching logic to only store dynamic patches if a valid hash can be generated, effectively skipping caching for non-serializable patches.
Activity
  • Added a test case to confirm that css.__withStyles does not crash when getDynamicPatch throws an error (theme-dependent css``).
  • Added a test case to confirm that css.__withStyles does not crash when JSON.stringify encounters circular references.
  • Verification for web rendering without circular reference errors is pending.
  • The pull request was generated using Claude Code.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

Warning

Rate limit exceeded

@hyochan has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 43 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 873cf9f6-bea3-4f3b-931a-0f4ecd12f9f0

📥 Commits

Reviewing files that changed from the base of the PR and between 54d2d96 and 1c7f842.

📒 Files selected for processing (4)
  • .claude/commands/commit.md
  • .claude/commands/review-pr.md
  • packages/kstyled/src/__tests__/runtime.test.tsx
  • packages/kstyled/src/css.tsx
📝 Walkthrough

Walkthrough

Enhanced dynamic-patch memoization in css.tsx with defensive error handling for getDynamicPatch and JSON serialization failures; caching only occurs for safe, non-empty hashes. Added two tests ensuring no crashes for theme-dependent failures and circular JSON values.

Changes

Cohort / File(s) Summary
Memoization & Defensive Guards
packages/kstyled/src/css.tsx
Added try/catch around getDynamicPatch({}) and JSON.stringify(...), fallback hash on failure, and guard logic to cache only when a non-empty, serializable hash exists.
Tests — runtime
packages/kstyled/src/__tests__/runtime.test.tsx
Added two tests: one ensuring no crash when getDynamicPatch throws (theme-dependent), another ensuring no crash when JSON.stringify encounters circular references.
Contributor Docs
.claude/commands/commit.md, .claude/commands/review-pr.md
Added new CLI/workflow docs describing commit and PR review procedures and templates (no code API changes).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

🍗 enhancement

Poem

🐰 A quick rabbit tests the night,
Hops 'round loops and theme's faint light.
When patches curl or JSON fights,
I guard the cache and calm the frights.
Little hops, robust delights ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding error handling for getDynamicPatch in the css.__withStyles function, which is the primary focus of the code modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/css-withstyles-error-handling
📝 Coding Plan
  • Generate coding plan for human review comments

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

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces error handling in css.__withStyles to prevent crashes from theme-dependent styles and circular references in dynamic patches. The changes are well-tested and correctly address the described issues. My review includes a couple of suggestions to improve the implementation: one to strengthen a test assertion for better regression detection, and another to add conditional debug logging for swallowed errors to aid in development, as silently catching all errors can mask unexpected issues.

Comment on lines +463 to +464
const result = css.__withStyles(metadata);
expect(result).toBeDefined();

Choose a reason for hiding this comment

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

medium

The assertion expect(result).toBeDefined() is quite weak. It only confirms that the function returns a value, but not what that value is. A more specific assertion would make this test more robust against future regressions. Since css.__withStyles returns the patch object itself when there's only one style, you can assert that the result is the circular object.

Suggested change
const result = css.__withStyles(metadata);
expect(result).toBeDefined();
const result = css.__withStyles(metadata);
expect(result).toBe(circular);

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed in 1c7f842.

Changes:

  • Changed expect(result).toBeDefined() to expect(result).toBe(circular) for stronger assertion
  • Added expect(metadata._cachedDynamic).toBeUndefined() to verify skip-caching contract

Comment on lines 234 to 239
} catch {
// getDynamicPatch({}) may fail when it contains theme-dependent
// functions (e.g., ({theme}) => theme.bg.basic) since {} has no theme.
// This is expected for css`` used inside styled components where
// theme is provided at render time, not at definition time.
}

Choose a reason for hiding this comment

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

medium

The catch block for errors within getDynamicPatch silently swallows all errors. While the comment explains this is expected for theme-dependent styles, it could unintentionally hide other types of errors during development, making debugging more difficult. It would be beneficial to log these errors when a debug flag is active to improve developer experience without adding noise to production builds.

        } catch (error) {
          if (metadata.debug) {
            console.warn('[kstyled] Error in getDynamicPatch during pre-evaluation (this is often expected for theme-dependent styles):', error);
          }
          // getDynamicPatch({}) may fail when it contains theme-dependent
          // functions (e.g., ({theme}) => theme.bg.basic) since {} has no theme.
          // This is expected for css`` used inside styled components where
          // theme is provided at render time, not at definition time.
        }

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed in 1c7f842.

Changes:

  • Added __DEV__ gated console.warn in the catch block to log errors during development without noise in production

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

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

🧹 Nitpick comments (2)
packages/kstyled/src/css.tsx (1)

234-239: Add debug-gated logging for swallowed getDynamicPatch failures.

This catch block currently hides all runtime errors, including non-theme-related regressions. Logging when metadata.debug or FALLBACK_DEBUG is enabled would keep the fail-safe behavior while improving diagnosability.

Proposed tweak
-        } catch {
+        } catch (error) {
           // getDynamicPatch({}) may fail when it contains theme-dependent
           // functions (e.g., ({theme}) => theme.bg.basic) since {} has no theme.
           // This is expected for css`` used inside styled components where
           // theme is provided at render time, not at definition time.
+          if (metadata.debug || FALLBACK_DEBUG) {
+            console.warn('[kstyled] css.__withStyles getDynamicPatch({}) failed', error);
+          }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/kstyled/src/css.tsx` around lines 234 - 239, The catch block
swallowing errors from getDynamicPatch({}) should log the caught error when
debugging is enabled; modify the catch in css.tsx around getDynamicPatch to
capture the thrown error (e.g., catch (err)) and, if metadata.debug or
FALLBACK_DEBUG is truthy, call the existing logger (or process.console) to emit
a concise debug message including the error and context (mention getDynamicPatch
and the related css/styled usage) while keeping the current silent behavior when
debug flags are not set.
packages/kstyled/src/__tests__/runtime.test.tsx (1)

449-465: Assert the “skip caching” contract explicitly in the circular-reference test.

Right now this only checks non-crash. Add an assertion that _cachedDynamic is not populated when serialization fails.

Suggested test addition
       // Should still push the patch even without caching
       const result = css.__withStyles(metadata);
       expect(result).toBeDefined();
+      expect(metadata._cachedDynamic).toBeUndefined();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/kstyled/src/__tests__/runtime.test.tsx` around lines 449 - 465,
Update the circular-reference test to also assert the "skip caching" contract:
after calling css.__withStyles(metadata) (both the non-throwing call and the
returned result), assert that the internal cache field css._cachedDynamic was
not populated for this metadata (i.e., remains undefined/empty) to confirm
serialization failure prevented caching; reference css.__withStyles, the
metadata.getDynamicPatch, and the internal css._cachedDynamic when adding the
assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/kstyled/src/__tests__/runtime.test.tsx`:
- Around line 449-465: Update the circular-reference test to also assert the
"skip caching" contract: after calling css.__withStyles(metadata) (both the
non-throwing call and the returned result), assert that the internal cache field
css._cachedDynamic was not populated for this metadata (i.e., remains
undefined/empty) to confirm serialization failure prevented caching; reference
css.__withStyles, the metadata.getDynamicPatch, and the internal
css._cachedDynamic when adding the assertion.

In `@packages/kstyled/src/css.tsx`:
- Around line 234-239: The catch block swallowing errors from
getDynamicPatch({}) should log the caught error when debugging is enabled;
modify the catch in css.tsx around getDynamicPatch to capture the thrown error
(e.g., catch (err)) and, if metadata.debug or FALLBACK_DEBUG is truthy, call the
existing logger (or process.console) to emit a concise debug message including
the error and context (mention getDynamicPatch and the related css/styled usage)
while keeping the current silent behavior when debug flags are not set.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 102f1165-35b8-4491-822d-4b73df6863e5

📥 Commits

Reviewing files that changed from the base of the PR and between 9a54fe0 and 45cfd56.

📒 Files selected for processing (2)
  • packages/kstyled/src/__tests__/runtime.test.tsx
  • packages/kstyled/src/css.tsx

Copy link

@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

🧹 Nitpick comments (1)
.claude/commands/commit.md (1)

121-121: Reformat the commit-types table for proper Markdown rendering.

The table is currently in a single line, which is hard to read/edit and may render inconsistently across tools.

Suggested doc fix
-**Commit Types:** | Type | Description | |------|-------------| | `feat` | New feature | | `fix` | Bug fix | | `docs` | Documentation only | | `refactor` | Code refactoring | | `chore` | Maintenance tasks | | `test` | Adding/updating tests | | `perf` | Performance improvement | | `style` | Code style (formatting, semicolons, etc.) |
+**Commit Types:**
+
+| Type       | Description                                 |
+|------------|---------------------------------------------|
+| `feat`     | New feature                                 |
+| `fix`      | Bug fix                                     |
+| `docs`     | Documentation only                          |
+| `refactor` | Code refactoring                            |
+| `chore`    | Maintenance tasks                           |
+| `test`     | Adding/updating tests                       |
+| `perf`     | Performance improvement                     |
+| `style`    | Code style (formatting, semicolons, etc.)  |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/commands/commit.md at line 121, The commit types table is currently
a single-line inline table that won't render properly; replace it with a proper
multi-line Markdown table by splitting into header, separator, and one row per
type (e.g., header: "Commit Types: | Type | Description", separator:
"|---|---|", then rows for `feat`, `fix`, `docs`, `refactor`, `chore`, `test`,
`perf`, `style`), ensuring code ticks around type tokens (e.g., `feat`) so the
table in .claude/commands/commit.md renders correctly and is easy to edit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/commands/commit.md:
- Around line 7-9: Add a fenced language tag to the code block containing the
command "/commit [options]" so markdown lint (MD040) passes; locate the
triple-backtick fence that wraps the line "/commit [options]" and change the
opening fence to include a language specifier (e.g., "```bash") so the block
becomes a proper fenced code block with a language.

In @.claude/commands/review-pr.md:
- Around line 91-96: Update the table example that contradicts the rule: replace
the "CORRECT | `Fixed in f3b5fec.`" cell so it shows plain text (e.g., CORRECT |
Fixed in f3b5fec.) instead of inline code, and ensure the explanatory text above
("NEVER wrap commit hashes in backticks or code blocks.") remains unchanged;
search for the table row containing the string "`Fixed in f3b5fec.`" to locate
and edit the example, removing backticks so the example aligns with the rule.

---

Nitpick comments:
In @.claude/commands/commit.md:
- Line 121: The commit types table is currently a single-line inline table that
won't render properly; replace it with a proper multi-line Markdown table by
splitting into header, separator, and one row per type (e.g., header: "Commit
Types: | Type | Description", separator: "|---|---|", then rows for `feat`,
`fix`, `docs`, `refactor`, `chore`, `test`, `perf`, `style`), ensuring code
ticks around type tokens (e.g., `feat`) so the table in
.claude/commands/commit.md renders correctly and is easy to edit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 86dc6746-2ff6-46e3-9f3d-bebf71a2d268

📥 Commits

Reviewing files that changed from the base of the PR and between 45cfd56 and 54d2d96.

📒 Files selected for processing (2)
  • .claude/commands/commit.md
  • .claude/commands/review-pr.md

- Strengthen circular reference test assertion (toBe instead of toBeDefined)
- Assert _cachedDynamic is undefined when serialization fails
- Add __DEV__ debug logging for swallowed getDynamicPatch errors
- Fix markdown lint: add language tag to fenced code block
- Fix contradictory commit-hash formatting example

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@hyochan hyochan merged commit a2b2233 into main Mar 13, 2026
5 checks passed
@hyochan hyochan deleted the fix/css-withstyles-error-handling branch March 13, 2026 07:50
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