Skip to content

fix(editor): guard GLB export against undefined array-material slots (Sentry MONOREPO-EDITOR-79)#459

Open
anton-pascal wants to merge 1 commit into
mainfrom
fix/sentry-EDITOR-79
Open

fix(editor): guard GLB export against undefined array-material slots (Sentry MONOREPO-EDITOR-79)#459
anton-pascal wants to merge 1 commit into
mainfrom
fix/sentry-EDITOR-79

Conversation

@anton-pascal

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

Copy link
Copy Markdown
Contributor

Summary

Follow-up hardening for Sentry MONOREPO-EDITOR-79TypeError: Cannot read properties of undefined (reading 'isShaderMaterial') (224 events, firing since 2026-04-22 through 2026-07-02) thrown from three GLTFExporter.processMaterialAsync during the automated GLB bake/thumbnail path (userCount:0).

The scalar-vs-array gap left by f75cffe

Commit f75cffed added a guard in pruneNonRenderableMeshes for renderables whose material is scalar null/undefined:

if ((renderable.isMesh || renderable.isLine || renderable.isPoints) && renderable.material == null) {  }

That only catches a scalar null. A mesh with an array material (multi-material / group geometry) where one slot was never assigned — e.g. mesh.material = [validMat, undefined] — is never == null, so it slips through. isRenderableMesh then returns true (the valid slot satisfies material.some((m) => m?.visible !== false)), so the mesh survives to GLTFExporter, which iterates every group's material and crashes on undefined.isShaderMaterial. That is the remaining trigger for this issue.

Fix

In pruneNonRenderableMeshes, after the existing scalar-null branch, handle the array case: for a renderable whose material is an array containing any null/undefined slot, fill the holes with the existing hidden PLACEHOLDER_MATERIAL and keep the mesh. The valid slots stay renderable; the exporter never sees an undefined material.

  • Scalar branch behavior is unchanged.
  • Reuses the existing PLACEHOLDER_MATERIAL constant.
  • Does not drop the whole mesh in the array case (other slots may be real geometry).

Tests

Added a prepareSceneForExport unit test covering material = [mat, undefined]: after prune, the array still has both slots and every slot is non-null (no undefined survives).

Note: bun test / check-types couldn't fully run in the isolated triage clone because the sibling workspace packages @pascal-app/core / @pascal-app/viewer aren't linked there (pre-existing, unrelated to this change). The change only touches local THREE.* usage and the existing PLACEHOLDER_MATERIAL.

Scope: packages/editor/src/lib/glb-export.ts and its test file only. No dependency changes.

Do not merge without review.


Note

Low Risk
Localized change to export-time mesh pruning with a matching unit test; no auth, data, or runtime behavior outside automated GLB bake.

Overview
Hardens GLB export against Sentry MONOREPO-EDITOR-79: meshes with multi-material arrays where a slot is undefined (e.g. [validMat, undefined]) no longer reach GLTFExporter, which used to throw on material.isShaderMaterial.

In pruneNonRenderableMeshes, after the existing scalar material == null handling, any array material with null/undefined slots is normalized by mapping holes to the existing hidden PLACEHOLDER_MATERIAL—the mesh is kept so valid slots still export.

Adds a prepareSceneForExport unit test asserting [mat, undefined] leaves a two-slot array with every entry non-null after prune.

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

@mintlify

mintlify Bot commented Jul 3, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
pascal 🔴 Failed Jul 3, 2026, 4:09 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@anton-pascal

Copy link
Copy Markdown
Contributor Author

Nightly Sentry triage (2026-07-06): MONOREPO-EDITOR-79 (isShaderMaterial) still firing in production (301 events, latest 2026-07-05 20:45 UTC, release 7838320f). Fix on this branch not yet deployed — this PR is still needed. No duplicate opened.

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.

1 participant