You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
console: changing the command-palette query after record hits have loaded blanks the whole console (cmdk "Cannot read properties of undefined (reading 'forEach')") #13387
Found during an exploratory walkthrough of the showcase app.
Environment
objectui main @ 6fb31dc, console served by pnpm --filter @object-ui/console dev (:5180)
objectstack main @ b9c7a8f, PORT=3000 pnpm dev (showcase), signed in as the dev admin, locale zh-CN
Chromium (Playwright), 1440×900
Steps
Open any app page, e.g. /apps/com.example.showcase/showcase_task.
Press Ctrl/⌘+K and type Website. Wait for the record hits (a 项目 group with Website Relaunch).
Change the query to something that returns a different set of record groups, either by select-all + typing 华宁 / Co, or by deleting the text with Backspace and typing Contoso.
Expected
The palette shows the hits for the new query.
Actual
The palette disappears and the entire console unmounts to an empty page (no shell, no sidebar); only a reload recovers. The page error is:
TypeError: Cannot read properties of undefined (reading 'forEach')
at .../node_modules/.vite/deps/cmdk.js:139:6
at Set.forEach (<anonymous>)
at z (.../cmdk.js:137:29)
at .../cmdk.js:106:5
at .../cmdk.js:483:28
at Map.forEach (<anonymous>)
...commitHookEffectListMount (react-dom_client.js)
followed by React's "An error occurred in the component. Consider adding an error boundary…".
Reproduced on every attempt (2/2 for each of the sequences above). A fresh query typed into a newly opened palette works (华宁, hn, Contoso, Data, 设置 all fine), and so does extending a query (Web → Website). It is the switch from one record-group set to another that crashes.
Reading of the cause (from the stack and the bundled cmdk 1.1.1 source, not debugged further)
cmdk's sort step (z in the minified build) walks state.filtered.groups and, for each id, reads that group's item set from its group map and calls .forEach on it. A CommandGroup that unmounts deletes its own map entry. In CommandPalette.tsx the record hits are rendered as one CommandGroup per object, keyed records:<objectName>, so when the new query stops returning an object that group unmounts while filtered.groups still names it, and the sort scheduled by an item's value change runs before the filter is recomputed. The lookup returns undefined and throws inside a layout effect.
Two separate things make it worse than a broken palette:
nothing above the palette catches the error, so one bad search takes down the whole console;
the record-group set is exactly the part of the palette that changes on every query, so ordinary use hits it.
Suggested direction
Make the record groups stable across queries (or let the async record hits bypass cmdk's own sort/filter, since their order and membership already come from /api/v1/search), and put an error boundary around the palette so a palette failure cannot unmount the shell.
Not a regression: this also reproduces on the released 18.0.0 console.
I reproduced it on the prebuilt @objectstack/console@18.0.0 from npm. Its dist/.objectui-sha is 616df6598b429d2b3687301a2041198928e68971. I served it same-origin, in front of the same objectstack main showcase backend, and signed in as the dev admin. Both sequences in the issue crash it the same way (2/2), with the same pageerror: Cannot read properties of undefined (reading 'forEach').
packages/components/src/ui/command.tsx is unchanged.
The lockfile pins cmdk@1.1.1 in both.
The per-object record groups (key={records:${group.objectName}}) were added in 8ecf5a6 (#2772, 2026-07-21), when the palette started showing /api/v1/search hits. That is most likely where the crash comes from. I have not bisected it build by build.
Triage: lands in apps/consoleCommandPalette.tsx (the per-object records:<objectName>CommandGroups) plus an error boundary around the palette in the shell; rationale: ordinary use of ⌘K (changing the query) unmounts the whole console. Not a regression: the filer reproduced it on the released 18.0.0 console (.objectui-sha616df65), most likely since #2772 added per-object record groups. Two parts: make the async record groups bypass cmdk's own sort/filter (or keep them stable across queries), and contain any palette failure so it cannot take the shell down.
Path: records · 搜得到…全局搜索与命令面板同一条路 | search.console-global-search (P1, fails on a changed query) | step ②
Grade: priority:p1 — inherits the P1 item, which fails; a whole-app white screen on a common action. Not P0: a reload recovers and nothing is lost. Release: it already ships in 18.0.0, so it does not make 18.1.0 worse; whether it holds the 18.1.0 cut is the maintainer's call, raised in the project thread.
Type: Bug
Session: session_01AkmasAfXt3cu83xGzkuKhe (objectstack triage, run on the maintainer's request in the project thread)
Claim: project thread seat (maintainer-dispatched) at 2026-10-23T17:20Z
Session: session_01Qfcwdm3pMxUcQjYXXJxRNt
Account: marchtian (the seat's linked user; the card's assignee)
Branch: claude/project-thread-zt8k65
Worktree: objectui-13387
Domain: domain:ui
Seat: domain:ui#1
File surface: packages/app-shell/src/chrome/ (CommandPalette.tsx plus one new test file beside it), one .changeset/*.md
Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate), effort: xhigh (p1)
Clause-②: no
Metadata-protocol: none
Responsibility: objectui app-shell CommandPalette: per-object record CommandGroups fed to cmdk's own sort/filter | none: nothing above the palette catches a render-phase or layout-effect error | every console user who changes a ⌘K query after record hits load; ordinary use today
Thread-read: 6370061042
Serial constraints cleared: none (no open PR touches CommandPalette.tsx or the palette; searched repo:objectstack-ai/objectui is:open CommandPalette and palette)
Dispatch provenance: the maintainer (田騏) ruled on the release decision card in the project thread, 2026-10-23T17:15Z, verbatim: 「不挡,现在就派人修」. This card does not block 18.1.0 and is worked now.
Plan, as the triage comment scopes it:
The palette already matches every entry it renders itself (matchesPaletteQuery), and record hits come ranked from /api/v1/search, so cmdk's own filter and sort are turned off (shouldFilter={false}). The crash is cmdk's sort walking a group id that an unmounted per-object group has already removed; with its filter off that sort never runs.
A palette failure is contained: an error boundary around the palette closes it and leaves the shell mounted, so the next ⌘K opens a fresh one.
A test reproduces the query switch between two different record-group sets.
Ruled (maintainer, 2026-10-23, decision card in the project thread, option A verbatim): 「不挡,现在就派人修」 — do not hold 18.1.0 for this card; dispatch it now.
Activity
marchtian commentedon Oct 23, 2026
Not a regression: this also reproduces on the released 18.0.0 console.
I reproduced it on the prebuilt
@objectstack/console@18.0.0from npm. Itsdist/.objectui-shais616df6598b429d2b3687301a2041198928e68971. I served it same-origin, in front of the same objectstackmainshowcase backend, and signed in as the dev admin. Both sequences in the issue crash it the same way (2/2), with the samepageerror: Cannot read properties of undefined (reading 'forEach').Between
616df6598and6fb31dcc9:CommandPalette.tsxis unchanged. The only edits there are theonSelecthandlers moving toconfirmUnsavedLeave(fix(app-shell): the command palette, the inbox and the AI entry ask before dropping unsaved edits (objectui#13253) #13265).packages/components/src/ui/command.tsxis unchanged.cmdk@1.1.1in both.The per-object record groups (
key={records:${group.objectName}}) were added in 8ecf5a6 (#2772, 2026-07-21), when the palette started showing/api/v1/searchhits. That is most likely where the crash comes from. I have not bisected it build by build.Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Triage: lands in
apps/consoleCommandPalette.tsx(the per-objectrecords:<objectName>CommandGroups) plus an error boundary around the palette in the shell; rationale: ordinary use of ⌘K (changing the query) unmounts the whole console. Not a regression: the filer reproduced it on the released 18.0.0 console (.objectui-sha616df65), most likely since #2772 added per-object record groups. Two parts: make the async record groups bypass cmdk's own sort/filter (or keep them stable across queries), and contain any palette failure so it cannot take the shell down.Path: records · 搜得到…全局搜索与命令面板同一条路 | search.console-global-search (P1, fails on a changed query) | step ②
Grade:
priority:p1— inherits the P1 item, which fails; a whole-app white screen on a common action. Not P0: a reload recovers and nothing is lost. Release: it already ships in 18.0.0, so it does not make 18.1.0 worse; whether it holds the 18.1.0 cut is the maintainer's call, raised in the project thread.Type: Bug
Session:
session_01AkmasAfXt3cu83xGzkuKhe(objectstack triage, run on the maintainer's request in the project thread)Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Claim: project thread seat (maintainer-dispatched) at 2026-10-23T17:20Z
Session:
session_01Qfcwdm3pMxUcQjYXXJxRNtAccount:
marchtian(the seat's linked user; the card's assignee)Branch:
claude/project-thread-zt8k65Worktree:
objectui-13387Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/app-shell/src/chrome/(CommandPalette.tsxplus one new test file beside it), one.changeset/*.mdContainer & model:
S,mode:thread,model: TIER_DEFAULT (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate),effort: xhigh (p1)Clause-②: no
Metadata-protocol: none
Responsibility:
objectui app-shell CommandPalette: per-object record CommandGroups fed to cmdk's own sort/filter|none: nothing above the palette catches a render-phase or layout-effect error|every console user who changes a ⌘K query after record hits load; ordinary use todayThread-read: 6370061042
Serial constraints cleared: none (no open PR touches
CommandPalette.tsxor the palette; searchedrepo:objectstack-ai/objectui is:open CommandPaletteandpalette)Dispatch provenance: the maintainer (田騏) ruled on the release decision card in the project thread, 2026-10-23T17:15Z, verbatim: 「不挡,现在就派人修」. This card does not block 18.1.0 and is worked now.
Plan, as the triage comment scopes it:
matchesPaletteQuery), and record hits come ranked from/api/v1/search, so cmdk's own filter and sort are turned off (shouldFilter={false}). The crash is cmdk's sort walking a group id that an unmounted per-object group has already removed; with its filter off that sort never runs.Generated by Claude Code
fix(app-shell): changing the ⌘K query no longer unmounts the console …
objectstack-fleet commentedon Oct 23, 2026
Ruled (maintainer, 2026-10-23, decision card in the project thread, option A verbatim): 「不挡,现在就派人修」 — do not hold 18.1.0 for this card; dispatch it now.
target:blocker. It already ships in 18.0.0 (.objectui-sha616df65), so 18.1.0 does not make it worse; 18.1.0 goes out when the pin PR chore(console): move the objectui pin 1d178e06ac5e → 6fb31dcc9954, past objectui#13370, so the console builds against the spec again objectstack#25455 lands.priority:p1,pm:queue,domain:ui— first in the objectuidomain:uiseat's queue. The fix ships with the next console pin bump after 18.1.0.Session:
session_01AkmasAfXt3cu83xGzkuKhe(objectstack triage, relaying the maintainer's ruling)Generated by Claude Code