{"record":{"id":"9aac57c7bd4e7366","repo":"BabylonJS/Babylon.js","slug":"cannot-rebuild-compound-part-proxy-name-the","errorCode":null,"errorMessage":"Cannot rebuild compound part \"${proxy.name}\": the retained compound source data is not available.","messagePattern":"Cannot rebuild compound part \"(.+?)\": the retained compound source data is not available\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.ts","lineNumber":1276,"sourceCode":"                    // scenario B, part 0 is itself a proxied part with no implicit \"own\" data.\r\n                    for (let partIndex = 0; partIndex < this._partProxies.length; partIndex++) {\r\n                        const proxy = this._partProxies[partIndex];\r\n                        if (!proxy) {\r\n                            continue;\r\n                        }\r\n                        // Streaming parts have no retained CPU source — their atlas rows (core + SH) are\r\n                        // GPU-authoritative and preserved across the rebuild by the backup/restore hooks. Leave their\r\n                        // rows at the fresh-array defaults (zero core, neutral SH) for the restore to overwrite; just\r\n                        // advance the offset. (With a static part present _splatsData is non-null and these would\r\n                        // otherwise reconstruct as a harmless zeros-slice; with only streaming parts it is null and\r\n                        // _createRetainedPartSource returns null — so this skip is required, not just an optimization.)\r\n                        if (this._streamingStates.some((s) => s.proxy === proxy)) {\r\n                            rebuildOffset += proxy._vertexCount;\r\n                            continue;\r\n                        }\r\n                        const source = this._createRetainedPartSource(proxy);\r\n                        if (!source) {\r\n                            throw new Error(`Cannot rebuild compound part \"${proxy.name}\": the retained compound source data is not available.`);\r\n                        }\r\n                        this._appendPartSourceToArrays(source, rebuildOffset, covA, covB, colorArray, sh, minimum, maximum);\r\n                        rebuildOffset += source._vertexCount;\r\n                    }\r\n                } else {\r\n                    // No proxies yet: this is the very first addPart call on a mesh that loaded\r\n                    // its own splat data (scenario A legacy path). Re-process that own data so\r\n                    // it occupies the start of the new texture before the incoming part is appended.\r\n                    // In the preferred scenario B (empty composer) splatCountA is 0 and this\r\n                    // entire branch is skipped by the outer `if (splatCountA > 0)` guard.\r\n                    if (this._splatsData) {\r\n                        const uBufA = GaussianSplattingMeshBase._GetSplatDataBytes(this._splatsData);\r\n                        const fBufA = GaussianSplattingMeshBase._GetSplatDataFloats(this._splatsData);\r\n                        for (let i = 0; i < splatCountA; i++) {\r\n                            this._makeSplat(i, fBufA, uBufA, covA, covB, colorArray, minimum, maximum, false);\r\n                        }\r\n                        if (sh && this._shData) {\r\n                            for (let texIdx = 0; texIdx < sh.length; texIdx++) {\r","sourceCodeStart":1258,"sourceCodeEnd":1294,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.ts#L1258-L1294","documentation":"During compound rebuild, for each non-streaming proxy part the mesh tries to recover its retained source data via `_createRetainedPartSource(proxy)`. If that returns null the original splat data for the part is no longer available (e.g. released after merge), so rebuilding the buffers would silently corrupt the compound — hence the throw naming the proxy mesh.","triggerScenarios":"Rebuilding a compound (e.g. after context loss, `rebuild()`, or re-adding parts to a loaded compound) when a proxy part's retained source data was discarded — data retention disabled, `dispose` of sources, or memory-saving flags that skip keeping `_splatsData`.","commonSituations":"WebGL context restore on a compound whose part sources were freed; re-serializing or re-merging a compound loaded from a file without retained sources; enabling memory-optimization options that release source data after merge.","solutions":["Keep the retained source data: don't dispose/release the original part `_splatsData` for meshes used as compound parts.","Avoid streaming-proxy marking mismatches: ensure `_streamingStates` correctly includes streaming proxies so they are skipped, not rebuilt.","Re-load the original part meshes from their source files before rebuilding the compound.","Wrap rebuild in try/catch and fall back to re-creating the compound from freshly loaded sources."],"exampleFix":"// before\ncompound.dispose(false); // releases retained part sources\n// ... later, on context restore\ncompound.rebuild();       // throws: source data gone\n\n// after\n// keep source splats data alive (do not dispose source meshes/data)\ncompound.rebuild();       // _createRetainedPartSource succeeds","handlingStrategy":"try-catch","validationCode":"for (const proxy of proxies) {\n    if (!compound._streamingStates.some(s => s.proxy === proxy) && !proxy._splatsData) {\n        // retained source missing: reload the original part from source files first\n        await reloadPartSource(proxy);\n    }\n}","typeGuard":"function canRebuildCompound(compound: GaussianSplattingMeshBase): boolean {\n    return compound._streamingStates.every(s =>\n        s.proxy._splatsData != null || s.proxy._isReservedEmpty);\n}","tryCatchPattern":"try {\n    compound.rebuild();\n} catch (e) {\n    if (e instanceof Error && e.message.includes(\"retained compound source data\")) {\n        const fresh = await reloadAllPartsFromFiles(); // re-decode original assets\n        return rebuildCompoundFrom(fresh);\n    }\n    throw e;\n}","preventionTips":["Don't dispose or release _splatsData of meshes used as compound parts if rebuild is expected","Keep original source files/URLs reachable so parts can be reloaded after context loss","Ensure streaming proxies are registered in _streamingStates so rebuild skips them","Prefer full re-creation of the compound over in-place rebuild when sources were freed"],"tags":["gaussian-splatting","compound","rebuild","missing-data","context-loss"],"backgroundTag":"retained-source-data-missing","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}