Skip to content

fix(core): guard material-ref parsers against non-string values (Sentry MONOREPO-EDITOR-EM)#486

Merged
Aymericr merged 2 commits into
mainfrom
fix/sentry-EDITOR-EM
Jul 19, 2026
Merged

fix(core): guard material-ref parsers against non-string values (Sentry MONOREPO-EDITOR-EM)#486
Aymericr merged 2 commits into
mainfrom
fix/sentry-EDITOR-EM

Conversation

@anton-pascal

@anton-pascal anton-pascal commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What

Add a typeof materialRef !== 'string' guard to getLibraryMaterialIdFromRef and getSceneMaterialIdFromRef in packages/core/src/material-library.ts.

Why

Both functions only guarded against null/undefined before calling .startsWith():

if (!materialRef) return null
if (!materialRef.startsWith(PREFIX)) return null   // throws if materialRef is a number/object

When a non-string material ref reaches them (a legacy or malformed wall material slot ref), .startsWith is undefined -> TypeError: e.startsWith is not a function.

Stack originates in wall material resolution: packages/viewer/src/systems/wall/wall-materials.ts -> parseMaterialRef(ref) -> getLibraryMaterialIdFromRef.

  • Sentry: MONOREPO-EDITOR-EM - new (first seen 7/8), 16 events / 2 users. Catching it before it grows.

Safety

typeof x !== 'string' narrows to string, so .startsWith/.slice remain valid; return type unchanged (non-string already mapped to null). Behaviour for real string refs is identical.

Verification

tsc --noEmit on @pascal-app/core: exit 0. biome check: clean.

Opened by nightly Sentry triage. Do not auto-merge - review first.


Note

Low Risk
Narrow defensive change in ref parsing; string behavior is unchanged and failures degrade to null like other invalid refs.

Overview
Hardens library and scene material ref parsing so malformed runtime values (numbers, booleans, objects) return null instead of throwing when .startsWith is invoked.

getLibraryMaterialIdFromRef and getSceneMaterialIdFromRef now bail out with typeof materialRef !== 'string' before prefix checks; scene parsing no longer relies on optional chaining alone on a possibly non-string ref. Valid string refs behave the same.

Adds a small Bun test that asserts both helpers return null for common non-string inputs, covering the wall material path that goes through parseMaterialRef.

Reviewed by Cursor Bugbot for commit 4b770d0. Bugbot is set up for automated code reviews on this repo. Configure here.

…ry MONOREPO-EDITOR-EM)

getLibraryMaterialIdFromRef and getSceneMaterialIdFromRef only guarded
against null/undefined, then called .startsWith(). When a non-string
material ref reaches them (legacy/malformed wall material slot ref),
.startsWith is undefined -> TypeError: e.startsWith is not a function.

Narrow with typeof !== 'string' -> return null, so a bad ref degrades to
'no library/scene material' instead of throwing during wall material
resolution (packages/viewer wall-materials.ts -> parseMaterialRef).
@anton-pascal

Copy link
Copy Markdown
Contributor Author

Nightly Sentry triage 2026-07-14: MONOREPO-EDITOR-EM is still firing in production (latest event 2026-07-14 01:57 UTC, release 4473110, editor.pascal.app). Confirmed the in-app stack matches this PR's target: packages/nodes/dist/column/renderer.js (depth material) -> packages/viewer .../materials.js:384 -> packages/core/.../material-library.js getLibraryMaterialIdFromRef. The typeof materialRef !== 'string' guard in this PR is the correct fix. Recommend review/merge.

@Aymericr
Aymericr merged commit f677870 into main Jul 19, 2026
3 checks passed
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.

2 participants