Skip to content

UI: Prevent crash when tag filters contain undefined entries#33931

Merged
yannbf merged 4 commits into
storybookjs:nextfrom
abhaysinh1000:fix/tags-filter-undefined
Feb 26, 2026
Merged

UI: Prevent crash when tag filters contain undefined entries#33931
yannbf merged 4 commits into
storybookjs:nextfrom
abhaysinh1000:fix/tags-filter-undefined

Conversation

@abhaysinh1000
Copy link
Copy Markdown
Contributor

@abhaysinh1000 abhaysinh1000 commented Feb 25, 2026

Closes #33803

What does this change?

Guards against undefined entries in the tag filters used by the manager sidebar.

Why is this needed?

When tags are configured globally but not yet used in any story, the filters
array can temporarily contain undefined entries during hot reload. The
sidebar assumed all filters were defined, which could cause a runtime crash:

Cannot read properties of undefined (reading 'type')

How was this tested?

  • Created a Storybook project with unused global tags configured
  • Renamed a story to trigger hot reload
  • Verified the sidebar no longer crashes

Summary by CodeRabbit

  • Refactor
    • Improved internal filter grouping and handling logic for greater reliability and maintainability. No changes to exported interfaces and no user-facing behavior or UI changes.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca3c9c2 and a7fab86.

📒 Files selected for processing (1)
  • code/core/src/manager/components/sidebar/TagsFilterPanel.tsx

📝 Walkthrough

Walkthrough

The change updates the groupByType implementation in TagsFilterPanel to first remove falsy entries with filters.filter(Boolean) and to initialize per-type arrays using nullish assignment (acc[filter.type] ??= []) instead of logical OR, keeping the same function signature. (39 words)

Changes

Cohort / File(s) Summary
Filter Grouping Logic
code/core/src/manager/components/sidebar/TagsFilterPanel.tsx
Reworked groupByType internals: falsy filters are filtered out before reducing, and per-type arrays are initialized with nullish assignment (??=) rather than logical OR (`

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
code/core/src/manager/components/sidebar/TagsFilterPanel.tsx (1)

151-151: ⚠️ Potential issue | 🟠 Major

Incomplete fix: hasUserTags is still vulnerable to the same undefined-entry crash.

The guard added inside groupByType protects line 140, but line 151 uses the same Object.values(filtersById) and immediately destructures { type } inside .some(...). An undefined entry in filtersById will still throw "Cannot destructure property 'type' of undefined" here, reproducing the original crash via a different path.

🐛 Proposed fix
-  const hasUserTags = Object.values(filtersById).some(({ type }) => type === 'tag');
+  const hasUserTags = Object.values(filtersById).some((filter) => filter?.type === 'tag');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/manager/components/sidebar/TagsFilterPanel.tsx` at line 151,
The hasUserTags computation is still vulnerable because
Object.values(filtersById).some(({ type }) => ...) will throw if an entry is
undefined; update the check used to compute hasUserTags (the hasUserTags
constant in TagsFilterPanel) to guard against undefined entries—e.g., iterate
safely by filtering out falsy values or by using a predicate like item => item
&& item.type === 'tag'—so it mirrors the defensive logic added in groupByType
and avoids destructuring undefined.
🧹 Nitpick comments (1)
code/core/src/manager/components/sidebar/TagsFilterPanel.tsx (1)

20-30: Tighten the type signature to reflect that undefined entries are the actual concern.

filters: Filter[] declares a non-nullable array, so TypeScript's strict mode sees .filter(Boolean) as a no-op type-wise and gives no narrowing. The runtime guard is correct, but the declared type doesn't communicate the intent. Consider widening the parameter type and using a type predicate for proper narrowing:

♻️ Proposed type-safe refactor
-export const groupByType = (filters: Filter[]) =>
-  filters
-    .filter(Boolean)
-    .reduce(
+export const groupByType = (filters: (Filter | undefined | null)[]) =>
+  filters
+    .filter((f): f is Filter => f != null)
+    .reduce(
       (acc, filter) => {
         acc[filter.type] ??= [];
         acc[filter.type].push(filter);
         return acc;
       },
       {} as Record<string, Filter[]>
     );

The call site at line 140 (Object.values(filtersById)) would need no change — TypeScript will accept it once the parameter type is widened.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/manager/components/sidebar/TagsFilterPanel.tsx` around lines 20
- 30, The parameter type for groupByType is too narrow—change the signature from
filters: Filter[] to filters: (Filter | undefined)[] (or Array<Filter |
undefined>) and update the filter call to use a type predicate so TypeScript
knows you're removing undefined values; keep the runtime .filter(Boolean) logic
but replace its type with a proper predicate or declare the function as (f): f
is Filter => Boolean(f) so the reducer sees only Filter items; reference
groupByType and the filters parameter when making this change (call sites like
Object.values(filtersById) need no modification).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@code/core/src/manager/components/sidebar/TagsFilterPanel.tsx`:
- Line 151: The hasUserTags computation is still vulnerable because
Object.values(filtersById).some(({ type }) => ...) will throw if an entry is
undefined; update the check used to compute hasUserTags (the hasUserTags
constant in TagsFilterPanel) to guard against undefined entries—e.g., iterate
safely by filtering out falsy values or by using a predicate like item => item
&& item.type === 'tag'—so it mirrors the defensive logic added in groupByType
and avoids destructuring undefined.

---

Nitpick comments:
In `@code/core/src/manager/components/sidebar/TagsFilterPanel.tsx`:
- Around line 20-30: The parameter type for groupByType is too narrow—change the
signature from filters: Filter[] to filters: (Filter | undefined)[] (or
Array<Filter | undefined>) and update the filter call to use a type predicate so
TypeScript knows you're removing undefined values; keep the runtime
.filter(Boolean) logic but replace its type with a proper predicate or declare
the function as (f): f is Filter => Boolean(f) so the reducer sees only Filter
items; reference groupByType and the filters parameter when making this change
(call sites like Object.values(filtersById) need no modification).

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22eff0e and ca3c9c2.

📒 Files selected for processing (1)
  • code/core/src/manager/components/sidebar/TagsFilterPanel.tsx

@yannbf yannbf self-assigned this Feb 25, 2026
@yannbf yannbf added bug ui patch:yes Bugfix & documentation PR that need to be picked to main branch tags ci:normal labels Feb 25, 2026
@yannbf yannbf changed the title fix(manager): prevent crash when tag filters contain undefined entries UI: Prevent crash when tag filters contain undefined entries Feb 25, 2026
@abhaysinh1000 abhaysinh1000 force-pushed the fix/tags-filter-undefined branch from 833049e to a7fab86 Compare February 26, 2026 08:16
@abhaysinh1000
Copy link
Copy Markdown
Contributor Author

CI seems to be failing in a flaky mobile E2E test
(Manager UI › Mobile › Open and close addon panel).

This does not appear related to the tag filter change.
Happy to re-run or adjust if needed.

@storybook-app-bot
Copy link
Copy Markdown

storybook-app-bot Bot commented Feb 26, 2026

Package Benchmarks

Commit: d20faea, ran on 26 February 2026 at 10:36:41 UTC

The following packages have significant changes to their size or dependencies:

@storybook/builder-webpack5

Before After Difference
Dependency count 188 188 0
Self size 76 KB 76 KB 🚨 +48 B 🚨
Dependency size 32.21 MB 32.22 MB 🚨 +11 KB 🚨
Bundle Size Analyzer Link Link

@storybook/ember

Before After Difference
Dependency count 192 192 0
Self size 15 KB 15 KB 🎉 -18 B 🎉
Dependency size 28.92 MB 28.93 MB 🚨 +11 KB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs

Before After Difference
Dependency count 535 535 0
Self size 648 KB 648 KB 0 B
Dependency size 59.87 MB 59.89 MB 🚨 +11 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-webpack5

Before After Difference
Dependency count 274 274 0
Self size 24 KB 24 KB 0 B
Dependency size 44.54 MB 44.55 MB 🚨 +11 KB 🚨
Bundle Size Analyzer Link Link

@storybook/server-webpack5

Before After Difference
Dependency count 200 200 0
Self size 16 KB 16 KB 🚨 +12 B 🚨
Dependency size 33.46 MB 33.47 MB 🚨 +11 KB 🚨
Bundle Size Analyzer Link Link

@storybook/preset-react-webpack

Before After Difference
Dependency count 170 170 0
Self size 18 KB 18 KB 🚨 +24 B 🚨
Dependency size 31.41 MB 31.42 MB 🚨 +11 KB 🚨
Bundle Size Analyzer Link Link

Copy link
Copy Markdown
Member

@yannbf yannbf left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution!

@yannbf yannbf merged commit 5a9c6ec into storybookjs:next Feb 26, 2026
114 of 115 checks passed
yannbf added a commit that referenced this pull request Mar 2, 2026
UI: Prevent crash when tag filters contain undefined entries
(cherry picked from commit 5a9c6ec)
@github-actions github-actions Bot added the patch:done Patch/release PRs already cherry-picked to main/release branch label Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug ci:normal patch:done Patch/release PRs already cherry-picked to main/release branch patch:yes Bugfix & documentation PR that need to be picked to main branch tags ui

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Cannot read properties of undefined (reading 'type')

2 participants