Batch.updateShows crash: `TypeError: Cannot read properties of undefined (reading 'id')` when toggling show + removing ground-clamped entity in same frame

Batch.updateShows crash: TypeError: Cannot read properties of undefined (reading 'id') when toggling show + removing ground-clamped entity in same frame

Summary

Toggling entity.show on a ground-clamped polyline (or polygon) and then removing it (or changing its material) in the same frame crashes the render loop with:

TypeError: Cannot read properties of undefined (reading 'id')
    at Batch.updateShows (StaticGroundPolylinePerMaterialBatch.js)
    at Batch.update
    at GeometryVisualizer.update
    at DataSourceDisplay.update
    at CesiumWidget.render

Sandcastle reproduction: link to sandcastle

Steps to reproduce

  1. Create a ground-clamped polyline entity (clampToGround: true)
  2. Wait for the ground primitive to compile
  3. In the same synchronous block:
    • Set entity.show = false
    • Call viewer.entities.remove(entity)
  4. The next render frame crashes

Root cause

Batch.prototype.remove() in StaticGroundPolylinePerMaterialBatch.js and StaticGroundGeometryPerMaterialBatch.js cleans up geometry, updaters, subscriptions — but does not call this.showsUpdated.remove(id).

When entity.show is toggled, the batch’s definitionChanged listener synchronously adds the updater to showsUpdated. If the entity is then removed before the next render, the sequence during GeometryVisualizer.update() is:

  1. Process removalsBatch.remove(updater)geometry.remove(id) ✓, but showsUpdated still has the entry
  2. Update batchesBatch.updateShows() → iterates showsUpdatedgeometry.get(updater.id) returns undefinedinstance.id crashes

The same issue occurs when an entity’s material changes (triggering batch migration) — the old batch retains the stale showsUpdated entry.

Affected files

  • @cesium/engine/Source/DataSources/StaticGroundPolylinePerMaterialBatch.js
  • @cesium/engine/Source/DataSources/StaticGroundGeometryPerMaterialBatch.js

Other batch files (StaticGeometryColorBatch, StaticGeometryPerMaterialBatch, StaticGroundGeometryColorBatch, StaticOutlineGeometryBatch) have the same potential issue in updateShows — they lack a null guard on instance after geometry.get().

Suggested fix

1. Add cleanup in Batch.prototype.remove() (primary fix):

Batch.prototype.remove = function (updater) {
  const id = updater.id;
  this.createPrimitive = this.geometry.remove(id) || this.createPrimitive;
  if (this.updaters.remove(id)) {
    this.updatersWithAttributes.remove(id);
    const unsubscribe = this.subscriptions.get(id);
    if (defined(unsubscribe)) {
      unsubscribe();
      this.subscriptions.remove(id);
+     this.showsUpdated.remove(id);   // clean up stale entry
    }
    return true;
  }
  return false;
};

2. Add defensive null check in Batch.prototype.updateShows() (belt-and-suspenders):

Batch.prototype.updateShows = function (primitive) {
  const showsUpdated = this.showsUpdated.values;
  const length = showsUpdated.length;
  for (let i = 0; i < length; i++) {
    const updater = showsUpdated[i];
    const instance = this.geometry.get(updater.id);
+   if (!defined(instance)) {
+     continue;
+   }
    // ... rest of method
  }
  this.showsUpdated.removeAll();
};

Environment

  • Cesium version: 1.120.0 (bug appears to be present in many versions)
  • Browser: Chrome 134
  • OS: macOS / Windows
1 Like

Welcome to the forum @Mahesh_Mali!

Thanks for the detailed information, CesiumJS is open source so you are welcome to head over to the github and create a Pull Request for your fix! You can also create a bug report here.

Sure @darcyvdd
Will create issue and submit PR soon!

These ‘batches’ are one of my pet peeves. You already mentioned that there are several places that are affected by this. I have not yet matched the issue here with the suggested changes. Specifically, I have not yet checked whether further places might be affected by this, depending on which ‘batch’ exactly is used under which conditions. The reason for why it is tedious to analyze this (and to make sure that it is fixed ‘everywhere’, and that it does not cause regressions) is summarized in Consolidate Batches in DataSources · Issue #12714 · CesiumGS/cesium · GitHub