{"record":{"id":"46faaf770f276a0a","repo":"BabylonJS/Babylon.js","slug":"to-call-addpart-addparts-each-source-mesh-mus-46faaf","errorCode":null,"errorMessage":"To call addPart()/addParts(), each source mesh must not be a compound","messagePattern":"To call addPart\\(\\)/addParts\\(\\), each source mesh must not be a compound","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.ts","lineNumber":1131,"sourceCode":"     *\r\n     * @param others - Source meshes to append (must each be non-compound and fully loaded)\r\n     * @param disposeOthers - Dispose source meshes after appending\r\n     * @returns Proxy meshes and their assigned part indices\r\n     */\r\n    protected _addPartsInternal(others: IGaussianSplattingPartSource[], disposeOthers: boolean): { proxyMeshes: GaussianSplattingPartProxyMesh[]; assignedPartIndices: number[] } {\r\n        if (others.length === 0) {\r\n            return { proxyMeshes: [], assignedPartIndices: [] };\r\n        }\r\n\r\n        // Validate\r\n        for (const other of others) {\r\n            // Reserved-empty placeholders (reserveStreamingPart) intentionally carry no splat data —\r\n            // their atlas region is left zeroed (invisible) for a streaming engine to decode into later.\r\n            if (!other._splatsData && !other._isReservedEmpty) {\r\n                throw new Error(`To call addPart()/addParts(), each source mesh must be fully loaded`);\r\n            }\r\n            if (other.isCompound) {\r\n                throw new Error(`To call addPart()/addParts(), each source mesh must not be a compound`);\r\n            }\r\n        }\r\n\r\n        const splatCountA = this._vertexCount;\r\n        const totalOtherCount = others.reduce((s, o) => s + o._vertexCount, 0);\r\n        const totalCount = splatCountA + totalOtherCount;\r\n\r\n        const textureSize = this._getTextureSize(totalCount);\r\n        const textureLength = textureSize.x * textureSize.y;\r\n        const covBSItemSize = this._useRGBACovariants ? 4 : 2;\r\n\r\n        // Allocate destination arrays for the full new texture\r\n        const covA = new Uint16Array(textureLength * 4);\r\n        const covB = new Uint16Array(covBSItemSize * textureLength);\r\n        const colorArray = new Uint8Array(textureLength * 4);\r\n\r\n        // Merged SH degree. The compound carries SH if any existing or new part has it, or a hosted stream bakes it.\r\n        // Parts without SH get neutral (128) fill. `_streamingShDegree` is the degree of the live SH streams (recomputed\r","sourceCodeStart":1113,"sourceCodeEnd":1149,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.ts#L1113-L1149","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Only add non-compound (single-part) splat meshes; keep the original individual meshes and merge those instead of the compound.","Check `other.isCompound` before merging and skip/reject those meshes.","Restructure to merge all leaves in a single addParts call rather than iteratively merging compounds."],"exampleFix":"// before\nconst ab = a.addParts([b]);   // ab.isCompound === true\nab.addParts([c]);              // throws\n\n// after\na.addParts([b, c]);            // merge all sources in one call","handlingStrategy":"validation","validationCode":"if (other.isCompound) {\n    throw new SkipSource(\"compound meshes cannot be parts\");\n}\ncompound.addParts([other]);","typeGuard":"function isNonCompoundSource(mesh: GaussianSplattingMeshBase): boolean {\n    return !mesh.isCompound;\n}","tryCatchPattern":"try {\n    compound.addParts(sources);\n} catch (e) {\n    if (e instanceof Error && e.message.includes(\"not be a compound\")) {\n        Logger.Warn(\"Merge leaves instead of compounds\");\n        return null;\n    }\n    throw e;\n}","preventionTips":["Merge all leaf splat meshes in a single addParts call; never chain merges of compounds","Keep references to original leaf meshes for later merges","Check isCompound on every source before merging","Never pass a compound back into addPart/addParts, including itself"],"tags":["gaussian-splatting","compound","validation"],"backgroundTag":"compound-source-not-allowed","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}