BabylonJS/Babylon.js · error · Error

To call addPart()/addParts(), each source mesh must not be a

Error message

To call addPart()/addParts(), each source mesh must not be a compound

What it means

The same addPart/addParts validation loop also rejects compound sources: if `other.isCompound` is true the mesh already consists of merged parts and cannot itself be added as a part. This prevents nested/flattened compound hierarchies.

Source

Thrown at packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.ts:1131

     *
     * @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);

        // Merged SH degree. The compound carries SH if any existing or new part has it, or a hosted stream bakes it.
        // Parts without SH get neutral (128) fill. `_streamingShDegree` is the degree of the live SH streams (recomputed

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Only add non-compound (single-part) splat meshes; keep the original individual meshes and merge those instead of the compound.
  2. Check `other.isCompound` before merging and skip/reject those meshes.
  3. Restructure to merge all leaves in a single addParts call rather than iteratively merging compounds.

Example fix

// before
const ab = a.addParts([b]);   // ab.isCompound === true
ab.addParts([c]);              // throws

// after
a.addParts([b, c]);            // merge all sources in one call
Defensive patterns

Strategy: validation

Validate before calling

if (other.isCompound) {
    throw new SkipSource("compound meshes cannot be parts");
}
compound.addParts([other]);

Type guard

function isNonCompoundSource(mesh: GaussianSplattingMeshBase): boolean {
    return !mesh.isCompound;
}

Try / catch

try {
    compound.addParts(sources);
} catch (e) {
    if (e instanceof Error && e.message.includes("not be a compound")) {
        Logger.Warn("Merge leaves instead of compounds");
        return null;
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling `a.addParts([b])` where `b` was previously built via `addPart`/`addParts` (isCompound === true), or passing the result of a previous compound merge as a source.

Common situations: Chaining merges (merge A+B, then merge result with C); reusing an already-merged mesh as a source in another scene's compound; accidentally adding a compound to itself or a sibling compound.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/46faaf770f276a0a. Report an issue: GitHub.