Found while measuring sibling colour keys for objectui#6178 (useRowColor is the sibling that fix mirrors). Not touched there — different package, outside that PR's file surface.
packages/plugin-grid/src/useRowColor.ts indexes two plain object literals with a string that comes from record data, with no own-property guard:
constvalue=String(row[config.field]??'');constcolor=config.colors[value];// author-declared map, indexed by a record valueif(!color)returnundefined;returncolorToClass(color);// -> color.startsWith('bg-')Both config.colors (an authored object) and COLOR_TO_CLASS (the module's literal) inherit Object.prototype, so a record whose colour field holds constructor, toString, valueOf, hasOwnProperty, … resolves to an inherited function rather than undefined. The if (!color) guard passes it (a function is truthy), and colorToClass then calls .startsWith on it.
Reproduction of the exact expression chain:
open colors[value] => string | result: bg-green-100
constructor THROWS: TypeError: color.startsWith is not a function
toString THROWS: TypeError: color.startsWith is not a function
valueOf THROWS: TypeError: color.startsWith is not a function
Consequence: the throw happens inside the row-className resolver during render, so it is a render crash of the grid, triggered by data rather than by metadata. A status/stage/category field that legitimately stores the string constructor is unusual but entirely representable — nothing in the schema forbids it, and the author's colors map does not have to mention the value for the crash to happen (the inherited member is found whether or not the author declared anything).
COLOR_TO_CLASS[lower] on line 52 has the same shape one call deeper: it would hand an Object.prototype member back as the row's className. That one does not throw — it reaches React as a class attribute — so it is the quieter half of the same defect.
Suggested shape, matching what objectui#6178 did for the analogous lookup in packages/plugin-detail/src/headerColor.ts: guard both indexes with Object.prototype.hasOwnProperty.call(map, key) (the workspace compiles against the ES2020 lib, so Object.hasOwn is not available), and pin a case whose field value is constructor.
Filed as an observation from adjacent work, unassigned — severity and disposition are a triage call. Back-link: objectui#6178, PR objectui#6294.
Found while measuring sibling colour keys for objectui#6178 (
useRowColoris the sibling that fix mirrors). Not touched there — different package, outside that PR's file surface.packages/plugin-grid/src/useRowColor.tsindexes two plain object literals with a string that comes from record data, with no own-property guard:Both
config.colors(an authored object) andCOLOR_TO_CLASS(the module's literal) inheritObject.prototype, so a record whose colour field holdsconstructor,toString,valueOf,hasOwnProperty, … resolves to an inherited function rather thanundefined. Theif (!color)guard passes it (a function is truthy), andcolorToClassthen calls.startsWithon it.Reproduction of the exact expression chain:
Consequence: the throw happens inside the row-className resolver during render, so it is a render crash of the grid, triggered by data rather than by metadata. A status/stage/category field that legitimately stores the string
constructoris unusual but entirely representable — nothing in the schema forbids it, and the author'scolorsmap does not have to mention the value for the crash to happen (the inherited member is found whether or not the author declared anything).COLOR_TO_CLASS[lower]on line 52 has the same shape one call deeper: it would hand anObject.prototypemember back as the row's className. That one does not throw — it reaches React as a class attribute — so it is the quieter half of the same defect.Suggested shape, matching what objectui#6178 did for the analogous lookup in
packages/plugin-detail/src/headerColor.ts: guard both indexes withObject.prototype.hasOwnProperty.call(map, key)(the workspace compiles against the ES2020 lib, soObject.hasOwnis not available), and pin a case whose field value isconstructor.Filed as an observation from adjacent work, unassigned — severity and disposition are a triage call. Back-link: objectui#6178, PR objectui#6294.