Repository navigation
[2.x] fix: stop ItemList.toArray() coercing null content to an empty object - #5000
Merged
Merged
Conversation
toArray() boxed every non-object item with Object() so the itemName proxy
could be attached. Object(null) is {}, so a null item became an empty
object, which Mithril treats as a vnode with an undefined tag and throws
"Cannot read properties of undefined (reading 'view')" on render.
PageStructure hits this when the sidebar attribute is omitted, taking the
whole page down. Any extension adding a conditional item as null hits it
too.
Null and undefined content now bypass the boxing path. Falsy primitives
are still boxed, so itemName stays readable on 0, false and ''.
imorland
added a commit
that referenced
this pull request
Aug 27, 2026
imorland
added a commit
that referenced
this pull request
Aug 27, 2026
imorland
added a commit
that referenced
this pull request
Aug 27, 2026
* chore: prep rc.8 * docs: add #5000 to the rc.8 changelog
8 of 13 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4998
Changes proposed in this pull request:
ItemList.toArray()attachesitemNameto each item by wrapping its content in a Proxy. Content that isn't already an object gets boxed first, withObject(item.content)— andObject(null)is{}. So an item added asnullcame out oftoArray()as an empty object. Mithril treats a plain object child as an already-normalized vnode, readsvnode.tag.viewininitComponent, and throwsTypeError: Cannot read properties of undefined (reading 'view').PageStructureis where this surfaces. It correctly guards the optional attribute:so omitting
sidebarputsnullinto the list, and the whole page fails to render.sidebaris documented as optional and typed as optional, so this is documented usage that crashes.PageStructure.tsx:86is the only place in core and the bundled extensions that puts a possibly-null value into anItemList, but the trap is in the shared utility: any extension writingitems.add('foo', condition ? <Foo /> : null)hits the same crash.Null and undefined content now skip the boxing path and pass through as-is. Mithril renders both as nothing, which is what the sidebar-less layout wants.
The check is explicitly against
null/undefinedrather than falsiness. A falsy check would box0,falseand''into{}too, breakingitemNameon them; there's a parameterised test pinning that down.This isn't a regression. The coercion is byte-identical in 1.8.19 — 2.x just shipped the first core component that feeds a null into an
ItemList.Reviewers should focus on:
toArray()never yieldingnull. Two call sites read a property straight off the result —Application.tsx:356(initializer.itemName) and package-manager'sQueueSection.tsx:186(item.label). Both now throw on property access where they previously got the{}proxy, but both then callinitializer(this)/content(task), so a null item already crashed a line later. Null was never valid in either list. I think that's the full extent of the behaviour change, and it's worth a second pair of eyes.<div class="Page-sidebar">should still render when no sidebar is given. This PR leaves it, since removing it changes the grid for anything styling that element. Happy to drop it if that's preferred, but it felt out of scope for a crash fix during RC.Screenshot
Not applicable — no visual change. The before/after is a page that renders versus a page that doesn't.
Necessity
<PageStructure />without asidebarattribute renders nothing and throws, per [2.x]<PageStructure />crashes when thesidebarattribute is omitted #4998.PageStructurealone (skip adding the item when no sidebar is given). That fixes the reported symptom but leaves the same landmine for any extension adding a conditional null item, so I fixed the utility instead.ItemListis core.Confirmed
yarn testinjs/). — core: 80 suites / 460 tests pass,check-typingsclean. Also ran the bundled extension frontend suites, which pull core's tests in: embed 475, mentions 463, tags 469, realtime 466, messages 460 — all pass.ItemListunit suite (core had none) covering null and undefined content, plus the boxing/ordering behaviour that must not change; and a newPageStructureintegration test rendering with a sidebar, without one, and with no attributes at all. The twoPageStructurecases fail on2.xwith the exact stack from the issue.composer test). — no backend changes.Required changes:
classNameas optional while the interface types it as required, andpaneisn't documented at all — both noticed while checking this report, neither touched here.