Skip to content

Fix: unrecoverable WASM crash when loading large SPZ Gaussian splat datasets#13287

Open
danielzhong wants to merge 4 commits intoDanielZ/Splat_FIX4from
DanielZ/Splat_FIX5
Open

Fix: unrecoverable WASM crash when loading large SPZ Gaussian splat datasets#13287
danielzhong wants to merge 4 commits intoDanielZ/Splat_FIX4from
DanielZ/Splat_FIX5

Conversation

@danielzhong
Copy link
Contributor

@danielzhong danielzhong commented Mar 9, 2026

Description

Loading SPZ Gaussian splat files with a high spherical harmonics degree (e.g. degree 3) and a large number of splats could cause the spz-loader WASM module to call Aborted(), producing an unrecoverable crash and an unhelpful "Aborted(). Build with -sASSERTIONS for more info." error message. This occurred because the WASM module is compiled with a signed 32-bit address space, imposing a hard 2 GB memory ceiling.

For example, a dataset of ~4.9 million splats at SH degree 3 requires approximately 2.2 GB to decode, exceeding that limit.

Changes:

  • Added a pre flight memory estimate in GltfSpzLoader.process() that runs before the WASM decoder is invoked.
  • Point count is read from the glTF POSITION accessor's count field; SH degree is inferred from the highest numbered SH_DEGREE_n attribute in the primitive. The SPZ binary itself cannot be inspected directly because it is gzip compressed.
  • If the estimated decoded size exceeds 1.6 GB (a conservative threshold below the 2 GB ceiling), the loader fails gracefully with a descriptive RuntimeError rather than crashing the WASM module.

Before:

Aborted()

After:

Error: Failed to load glTF
Failed to load vertex buffer
Failed to load SPZ
SPZ data too large to decode: 4,913,000 splats with spherical harmonics degree 3 would require approximately 2212 MB, which exceeds the WASM memory limit. Consider using a lower spherical harmonics degree or splitting the dataset into smaller tiles.

Issue number and link

#13283

Testing plan

Test data:
#13283

Author checklist

  • I have submitted a Contributor License Agreement
  • I have added my name to CONTRIBUTORS.md
  • I have updated CHANGES.md with a short summary of my change
  • I have added or updated unit tests to ensure consistent code coverage
  • I have updated the inline documentation, and included code examples where relevant
  • I have performed a self-review of my code

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Thank you for the pull request, @danielzhong!

✅ We can confirm we have a CLA on file for you.

@danielzhong danielzhong changed the base branch from main to DanielZ/Splat_FIX4 March 9, 2026 21:26
@javagl
Copy link
Contributor

javagl commented Mar 10, 2026

It's good to see the reason for the issue being identified.

I don't fully understand the 2.2 GB. With position, scale, opacity, rotation, and the 15*3 SH coefficients, that would be
4900000 * (3 + 3 + 1 + 4 + 45) * 4 ~= 1 GB
but maybe I'm missing some place where all this is double (last factor being 8 instead of 4).

However, when you say

This occurred because the WASM module is compiled with a signed 32-bit address space

I wonder: Is it possible to ~"compile this with 64 bit address space"? Maybe something to raise as an issue in https://github.com/drumath2237/spz-loader ?

The point is: Apparently, tools (including ion!) have already created data sets that cause this error. And I wonder whether it's possible to handle this on the client side. Otherwise, people would 1. have to wait until this is fixed, so that ion does no longer create data sets that cause this error, and 2. then have to re-tile their data...

@danielzhong
Copy link
Contributor Author

danielzhong commented Mar 10, 2026

It's good to see the reason for the issue being identified.

I don't fully understand the 2.2 GB. With position, scale, opacity, rotation, and the 15*3 SH coefficients, that would be 4900000 * (3 + 3 + 1 + 4 + 45) * 4 ~= 1 GB but maybe I'm missing some place where all this is double (last factor being 8 instead of 4).

However, when you say

This occurred because the WASM module is compiled with a signed 32-bit address space

I wonder: Is it possible to ~"compile this with 64 bit address space"? Maybe something to raise as an issue in https://github.com/drumath2237/spz-loader ?

The point is: Apparently, tools (including ion!) have already created data sets that cause this error. And I wonder whether it's possible to handle this on the client side. Otherwise, people would 1. have to wait until this is fixed, so that ion does no longer create data sets that cause this error, and 2. then have to re-tile their data...

Math:
Yes, the decoded output alone is roughly 4,900,000 × (3+3+1+4+45) × 4 ≈ 1.1 GB. The ×2 factor in the estimate is conservative during gzip decompression, the compressed stream and the decoded output coexist briefly on the WASM heap alongside zlib's working buffers, which can push peak usage well above the final output size.

On Memory64:
I have opened an issue on spz-loader to raise this.
drumath2237/spz-loader#75

@lukemckinstry

This comment was marked as resolved.

@lukemckinstry
Copy link
Contributor

I see the enhanced error message as described. (disregard my previous resolved comment as I was testing the wrong branch)

My only questions:

  • Are we handling incomplete/malformed glTF JSON?
  • Is it appropriate to add unit tests?

@danielzhong
Copy link
Contributor Author

  • Are we handling incomplete/malformed glTF JSON?

The preflight is best effort. If the glTF JSON does not contain the metadata needed for the estimate, we skip the estimate rather than failing on the JSON itself. So this change should not introduce a new failure mode for incomplete/malformed glTF JSON.

That said, if the required metadata is missing, we also cannot preflight the SPZ size, so in that case the loader falls back to the existing decode path.

I added a lightweight unit test around the preflight estimate / early-failure path. I think that is the right level of coverage here, since the goal of this change is to verify our guard logic before invoking the WASM decoder, rather than exercising the full GLB loading path or the downstream SPZ library itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants