BabylonJS/Babylon.js · error · Error
To call addPart()/addParts(), each source mesh must be fully
Error message
To call addPart()/addParts(), each source mesh must be fully loaded
What it means
The GaussianSplattingMesh addPart/addParts validation throws when a source mesh (`other`) has no `_splatsData` and is not a reserved-empty streaming placeholder — i.e. it hasn't finished loading/decoding its splat data. Compound meshes cannot be added; parts must be fully decoded first.
Source
Thrown at packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.ts:1128
* Core implementation for adding one or more source parts as new
* parts. Writes directly into texture-sized CPU arrays, updates the retained merged source
* buffers, and uploads in one pass.
*
* @param others - Source meshes to append (must each be non-compound and fully loaded)
* @param disposeOthers - Dispose source meshes after appending
* @returns Proxy meshes and their assigned part indices
*/
protected _addPartsInternal(others: IGaussianSplattingPartSource[], disposeOthers: boolean): { proxyMeshes: GaussianSplattingPartProxyMesh[]; assignedPartIndices: number[] } {
if (others.length === 0) {
return { proxyMeshes: [], assignedPartIndices: [] };
}
// Validate
for (const other of others) {
// Reserved-empty placeholders (reserveStreamingPart) intentionally carry no splat data —
// their atlas region is left zeroed (invisible) for a streaming engine to decode into later.
if (!other._splatsData && !other._isReservedEmpty) {
throw new Error(`To call addPart()/addParts(), each source mesh must be fully loaded`);
}
if (other.isCompound) {
throw new Error(`To call addPart()/addParts(), each source mesh must not be a compound`);
}
}
const splatCountA = this._vertexCount;
const totalOtherCount = others.reduce((s, o) => s + o._vertexCount, 0);
const totalCount = splatCountA + totalOtherCount;
const textureSize = this._getTextureSize(totalCount);
const textureLength = textureSize.x * textureSize.y;
const covBSItemSize = this._useRGBACovariants ? 4 : 2;
// Allocate destination arrays for the full new texture
const covA = new Uint16Array(textureLength * 4);
const covB = new Uint16Array(covBSItemSize * textureLength);
const colorArray = new Uint8Array(textureLength * 4);
View on GitHub (pinned to 0592b347b8)
Solutions
- Await each source mesh's load/decode promise (e.g. `await other.whenReadyAsync()` or the promise from GaussianSplattingMesh creation) before addParts.
- Check `other._splatsData` (or a public loaded flag/`isReady`) for every source before merging.
- If using streaming, mark intentional placeholders via `reserveStreamingPart` instead of passing unloaded meshes.
Example fix
// before
const a = await GaussianSplattingMesh.Parse(...urlA...);
const b = new GaussianSplattingMesh("b", urlB, scene); // not awaited
a.addParts([b]);
// after
const a = await GaussianSplattingMesh.Parse(...urlA...);
const b = await new GaussianSplattingMesh("b", urlB, scene).whenReadyAsync(); // ensure loaded
a.addParts([b]); Defensive patterns
Strategy: validation
Validate before calling
if (!other._splatsData && !other._isReservedEmpty) {
await other.whenReadyAsync(); // or the mesh's load promise
}
mesh.addParts([other]); Type guard
function isSplatsSourceLoaded(mesh: GaussianSplattingMeshBase): boolean {
return !!mesh._splatsData || mesh._isReservedEmpty;
} Try / catch
try {
compound.addParts(sources);
} catch (e) {
if (e instanceof Error && e.message.includes("fully loaded")) {
await Promise.all(sources.map(s => s.whenReadyAsync()));
return compound.addParts(sources);
}
throw e;
} Prevention
- Always await the loading promise of each source splat mesh before addPart/addParts
- Track pending loads and queue merges until all sources resolve
- Use reserveStreamingPart for intentional empty placeholders instead of unloaded meshes
- Handle load failures so sources don't silently remain unloaded
When it happens
Trigger: Calling `mesh.addParts([other])` where `other` is still loading from a .splat/.ply/.ksplat URL (its async decode hasn't resolved, so `_splatsData` is undefined), or passing a mesh constructed but never awaited.
Common situations: Building a compound splat from several downloaded assets without awaiting each one; queuing addParts immediately after construction; a failed load leaving `_splatsData` null.
Related errors
- To call addPart()/addParts(), each source mesh must not be a
- Cannot add part, as the maximum part count (${maxPartCount})
- Cannot rebuild compound part "${proxy.name}": the retained c
- GaussianSplattingDebugger.addMesh: mesh must have a Gaussian
- reserveStreamingPart: shTextureCount ${shTextureCount} does
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/92b1d4feb4d35820.
Report an issue: GitHub.