{"record":{"id":"8abe71375c29581b","repo":"BabylonJS/Babylon.js","slug":"cannot-add-part-as-the-maximum-part-count-maxp","errorCode":null,"errorMessage":"Cannot add part, as the maximum part count (${maxPartCount}) has been reached","messagePattern":"Cannot add part, as the maximum part count \\((.+?)\\) has been reached","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.ts","lineNumber":1200,"sourceCode":"        // --- Build part indices ---\r\n        let nextPartIndex = this.partCount;\r\n        let partIndicesA = this._partIndices;\r\n        if (!partIndicesA) {\r\n            // First addPart on a plain mesh: assign its splats to part 0\r\n            partIndicesA = new Uint8Array(splatCountA);\r\n            nextPartIndex = splatCountA > 0 ? 1 : 0;\r\n        }\r\n\r\n        this._partIndices = new Uint8Array(textureLength);\r\n        this._partIndices.set(partIndicesA.subarray(0, splatCountA));\r\n\r\n        const assignedPartIndices: number[] = [];\r\n        const assignedSplatsDataOffsets: number[] = [];\r\n        let dstOffset = splatCountA;\r\n        const maxPartCount = GetGaussianSplattingMaxPartCount(this._scene.getEngine());\r\n        for (const other of others) {\r\n            if (nextPartIndex >= maxPartCount) {\r\n                throw new Error(`Cannot add part, as the maximum part count (${maxPartCount}) has been reached`);\r\n            }\r\n            const newPartIndex = nextPartIndex++;\r\n            assignedPartIndices.push(newPartIndex);\r\n            assignedSplatsDataOffsets.push(dstOffset);\r\n            this._partIndices.fill(newPartIndex, dstOffset, dstOffset + other._vertexCount);\r\n            dstOffset += other._vertexCount;\r\n        }\r\n\r\n        // --- Process source data ---\r\n        if (!incremental) {\r\n            // Full rebuild path — only reached when the GPU texture must be reallocated\r\n            // (either the texture height needs to grow to fit the new total, or this is\r\n            // the very first addPart onto a mesh with no GPU textures yet). In the common\r\n            // case where the texture height is unchanged, `incremental` is true and this\r\n            // entire block is skipped. The `splatCountA > 0` guard avoids redundant work\r\n            // on the first-ever addPart when the compound mesh starts empty.\r\n            if (splatCountA > 0) {\r\n                if (this._partProxies.length > 0) {\r","sourceCodeStart":1182,"sourceCodeEnd":1218,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.ts#L1182-L1218","documentation":"Gaussian splatting compounds use a per-part index attribute whose size is capped by the engine (GetGaussianSplattingMaxPartCount). addPart/addParts throws once `nextPartIndex` would exceed that maximum, because there are no remaining part slots to assign to the new source meshes.","triggerScenarios":"Repeatedly calling `addPart()`/`addParts()` on one compound mesh until the number of parts exceeds GetGaussianSplattingMaxPartCount(engine) (GPU-dependent, often small, e.g. 8/16); merging many small splat meshes into one compound.","commonSituations":"Streaming scenarios appending parts over time; merging dozens of chunk files; hardware with a low max part count (weaker GPUs/WebGL limits) while testing on a device with a higher cap.","solutions":["Check the current part count against `GetGaussianSplattingMaxPartCount(engine)` before adding and batch/limit merges accordingly.","Merge multiple sources into fewer addParts calls only up to the cap; split the compound into several meshes beyond that.","Query the cap early and design streaming chunk size so total parts stay within it.","On catch, stop appending and create a new compound mesh for subsequent parts."],"exampleFix":"// before\nwhile (chunks.length) {\n    compound.addPart(chunks.pop()!); // eventually throws\n}\n\n// after\nconst max = GetGaussianSplattingMaxPartCount(engine);\nwhile (chunks.length && compound.partCount < max) {\n    compound.addPart(chunks.pop()!);\n}","handlingStrategy":"validation","validationCode":"const max = GetGaussianSplattingMaxPartCount(engine);\nconst free = max - compound.partCount;\nif (others.length > free) {\n    // split: add up to free parts, start a new compound for the rest\n}","typeGuard":"function canAddParts(compound: GaussianSplattingMeshBase, count: number): boolean {\n    return compound.partCount + count <= GetGaussianSplattingMaxPartCount(compound.getScene().getEngine());\n}","tryCatchPattern":"try {\n    compound.addParts(sources);\n} catch (e) {\n    if (e instanceof Error && e.message.includes(\"maximum part count\")) {\n        const max = GetGaussianSplattingMaxPartCount(engine);\n        compound.addParts(sources.slice(0, max - compound.partCount));\n        return createNewCompound(sources.slice(max - compound.partCount));\n    }\n    throw e;\n}","preventionTips":["Query GetGaussianSplattingMaxPartCount(engine) at startup and design chunking below it","Track current part count before each addPart/addParts call","Test on the lowest-capability target GPU, not just dev hardware","Split oversized merges across multiple compound meshes"],"tags":["gaussian-splatting","limit-exceeded","gpu-limits","compound"],"backgroundTag":"max-part-count-exceeded","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}