How to Fix: crash running all the wasmtime and wasm-tools component WASTs together

6 min read

When wasmtime wast crashes on the full component WAST suite, the problem is usually not a single malformed test file—it is an interaction bug triggered by running many component-model tests in one process with experimental features enabled at the same time.

Symptoms and Reproduction

This issue appears when invoking wasmtime against a large combined set of WAST files from wasmtime and wasm-tools, especially when enabling multiple experimental component flags such as component-model-async, async builtins, and component-model-threading.

A typical failing command looks like this:

wasmtime wast \
  -W component-model-async=y \
  -W component-model-async-builtins=y \
  -W component-model-threading=y \
  path/to/combined/tests/*.wast

Instead of getting a clean pass/fail result for each test, the process may crash, abort unexpectedly, or fail only when many files are executed together.

This pattern strongly suggests a global-state, engine reuse, or feature interaction problem rather than a single standalone parser error.

Understanding the Root Cause

The root cause is typically that the full suite of component WASTs exercises incompatible or insufficiently isolated execution paths inside the same wasmtime wast process. When all component tests are run together, several low-level behaviors compound:

  • Shared process state: Running many WAST files in one invocation can reuse internal state across test boundaries, including engine configuration, linker state, component instantiation metadata, or async-related runtime structures.
  • Experimental feature overlap: Flags like component-model-async, component-model-async-builtins, and component-model-threading activate code paths that are still evolving. Some WASTs may be valid independently, but combining them can expose assumptions that do not hold when all features are enabled together.
  • Test suite composition mismatch: The wasmtime and wasm-tools suites are not always authored with the expectation that every file will run under one identical feature matrix in one long-lived CLI session.
  • State leakage between modules/components: If a prior test leaves behind state that changes how a later component is validated, instantiated, or executed, the crash may only appear in the aggregate run.

In short, this is a classic cross-test isolation bug. The crash occurs because the combined run exposes an internal assumption that is not violated when the same WASTs are executed individually or in smaller groups.

Step-by-Step Solution

The safest workaround is to stop treating the entire component WAST corpus as one monolithic invocation. Run tests in isolated batches, keep the feature set minimal for each batch, and bisect the failing subset to identify the specific interaction.

1. Confirm the crash only happens in the aggregate run

wasmtime wast \
  -W component-model-async=y \
  -W component-model-async-builtins=y \
  -W component-model-threading=y \
  test1.wast

Repeat for a few individual files. If single-file runs pass but the combined run crashes, that confirms a test interaction issue.

2. Run each WAST in a fresh process

Instead of one large shell expansion, invoke wasmtime once per file:

for f in path/to/combined/tests/*.wast; do
  echo "Running $f"
  wasmtime wast \
    -W component-model-async=y \
    -W component-model-async-builtins=y \
    -W component-model-threading=y \
    "$f" || break
done

This avoids process-level state reuse and is often enough to prevent the crash.

3. Bisect the failing file set

If the crash still occurs only after a certain sequence, split the suite into halves:

mkdir -p /tmp/wast-bisect
ls path/to/combined/tests/*.wast > /tmp/wast-bisect/all.txt
split -n l/2 /tmp/wast-bisect/all.txt /tmp/wast-bisect/chunk-

Then run each chunk:

while read -r f; do
  wasmtime wast \
    -W component-model-async=y \
    -W component-model-async-builtins=y \
    -W component-model-threading=y \
    "$f" || exit 1
done < /tmp/wast-bisect/chunk-aa

This helps identify whether the bug is tied to one specific file or to an ordering-sensitive interaction between multiple files.

4. Reduce the enabled feature matrix

Try removing one experimental feature at a time:

wasmtime wast -W component-model-async=y test.wast
wasmtime wast -W component-model-async-builtins=y test.wast
wasmtime wast -W component-model-threading=y test.wast

Then test combinations:

wasmtime wast \
  -W component-model-async=y \
  -W component-model-async-builtins=y \
  test.wast

If the crash only occurs under one specific combination, you have narrowed the issue to a feature interaction regression.

5. Pin to a known good revision or update beyond the failing dev build

Because the issue is reported against the current dev release, check whether it has already been fixed upstream. Pull the latest code and rebuild:

git clone wasmtime repository
cd wasmtime
cargo build --release

Then rerun your isolated reproduction. If the crash disappears, the bug was likely fixed after the failing snapshot. If not, use git bisect between a known good and bad revision.

6. Produce a minimal reproducible report

If you need to open or update the issue, provide:

  • The exact wasmtime commit or version
  • The exact CLI flags
  • The smallest ordered list of WAST files that triggers the crash
  • Whether the same files pass individually
  • Any backtrace from a debug build

A debug-friendly run may look like this:

RUST_BACKTRACE=1 target/release/wasmtime wast \
  -W component-model-async=y \
  -W component-model-async-builtins=y \
  -W component-model-threading=y \
  problematic.wast

If you build an unoptimized debug binary, the stack trace is often more actionable for maintainers.

7. Use a practical CI workaround

For continuous integration, prefer isolated execution until the upstream fix lands:

find path/to/combined/tests -name '*.wast' -print0 | while IFS= read -r -d '' f; do
  wasmtime wast \
    -W component-model-async=y \
    -W component-model-async-builtins=y \
    -W component-model-threading=y \
    "$f" || exit 1
done

This preserves test coverage while avoiding the unstable all-in-one invocation pattern.

Common Edge Cases

  • Order-dependent failures: File A followed by File B may crash, while B followed by A does not. That is a strong sign of leaked internal state.
  • Shell argument explosion: Very large globs can hit shell or OS argument-size limits. That can mask the real problem or make failures appear inconsistent.
  • Mismatched test expectations: Some WASTs may assume features are disabled unless explicitly requested. Running every file with every experimental flag enabled can create invalid combinations.
  • Debug vs release differences: A release build may hard-crash where a debug build emits a panic or assertion, so always test both when narrowing root cause.
  • Outdated wasm-tools fixtures: If the wasm-tools test corpus and your wasmtime dev build are from different points in development, incompatibilities can appear that are not true runtime bugs.

FAQ

Why do the WAST files pass individually but crash together?

Because the failure is likely caused by shared runtime state or a feature interaction that only appears when multiple component tests execute in the same process.

Is this a bad test file or a wasmtime bug?

If the same files run correctly in isolation and only fail in aggregate, it is much more likely to be a wasmtime isolation bug, a regression, or an unsupported combination in the current dev build.

What is the best immediate workaround?

Run each .wast file in a separate wasmtime process, reduce the enabled experimental flags to the minimum required, and report the smallest reproducing file sequence upstream.

The key fix strategy is simple: avoid one giant multi-file invocation, isolate each WAST execution, and narrow the exact feature combination that triggers the crash. That gives you a stable short-term workflow and the precise evidence needed for an upstream patch.

Leave a Reply

Your email address will not be published. Required fields are marked *