wasmerio/wasmer · error

Unhandled inner case

Error message

Unhandled inner case

What it means

An explicit `unreachable!("Unhandled inner case")` panic inside `translate_conversion_operator` in wasmer's LLVM backend. For the SIMD `I64x2Extend*I32x4*` conversion operators the code builds a nested match to pick the extend closure (zero- vs sign-extend); if the outer match dispatched an operator the inner match does not enumerate, the inner wildcard at code.rs:8771 panics. This indicates an inconsistency between the outer operator dispatch and the inner operator refinement — reached only when a conversion operator's inner selection was not covered, usually due to a bug or a non-standard/new operator variant.

Source

Thrown at lib/compiler-llvm/src/translator/code.rs:8771

                );
                let res = err!(
                    self.builder
                        .build_bit_cast(res, self.intrinsics.i128_ty, "")
                );
                self.state.push1(res);
            }
            Operator::I64x2ExtendLowI32x4U
            | Operator::I64x2ExtendLowI32x4S
            | Operator::I64x2ExtendHighI32x4U
            | Operator::I64x2ExtendHighI32x4S => {
                let extend = match op {
                    Operator::I64x2ExtendLowI32x4U | Operator::I64x2ExtendHighI32x4U => {
                        |s: &Self, v| s.builder.build_int_z_extend(v, s.intrinsics.i64x2_ty, "")
                    }
                    Operator::I64x2ExtendLowI32x4S | Operator::I64x2ExtendHighI32x4S => {
                        |s: &Self, v| s.builder.build_int_s_extend(v, s.intrinsics.i64x2_ty, "")
                    }
                    _ => unreachable!("Unhandled inner case"),
                };
                let indices = match op {
                    Operator::I64x2ExtendLowI32x4S | Operator::I64x2ExtendLowI32x4U => {
                        [self.intrinsics.i32_consts[0], self.intrinsics.i32_consts[1]]
                    }
                    Operator::I64x2ExtendHighI32x4S | Operator::I64x2ExtendHighI32x4U => {
                        [self.intrinsics.i32_consts[2], self.intrinsics.i32_consts[3]]
                    }
                    _ => unreachable!("Unhandled inner case"),
                };
                let (v, i) = self.state.pop1_extra()?;
                let (v, _) = self.v128_into_i32x4(v, i)?;
                let low = err!(self.builder.build_shuffle_vector(
                    v,
                    v.get_type().get_undef(),
                    VectorType::const_vector(&indices),
                    "",
                ));

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Use the Cranelift backend for this module instead of LLVM
  2. Upgrade wasmer and wasmer-compiler-llvm to a version covering the conversion operator
  3. Recompile the module without the offending SIMD conversion instructions (disable simd128/relaxed-simd)
  4. Validate the module with restrictive feature flags before compilation so this becomes a proper compile error
  5. If the operator is standard and present in upstream wasmer, file a bug with the module and wasmer version

Example fix

// before
let engine = Engine::from(LLVM::new());
// after
let engine = Engine::from(Cranelift::new());
Defensive patterns

Strategy: try-catch

Validate before calling

fn validate_before_compile(engine: &wasmer::Engine, wasm: &[u8]) -> Result<(), String> {
    wasmer::Module::validate(engine, wasm)
        .map_err(|e| format!("unsupported conversion op (SIMD extend?): {e}"))
}

Type guard

fn has_simd_conversion_ops(wasm: &[u8]) -> bool {
    // SIMD conversions use the 0xFD prefix opcode space
    wasm.windows(2).any(|w| w[0] == 0xFD)
}

Try / catch

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    wasmer::Module::new(&llvm_engine, &wasm)
}));
match result {
    Ok(Ok(module)) => Ok(module),
    Ok(Err(e)) => Err(e.into()),
    Err(_) => {
        log::warn("wasmer LLVM panic (unhandled conversion case); retrying with Cranelift");
        wasmer::Module::new(&cranelift_engine, &wasm).map_err(Into::into)
    }
}

Prevention

When it happens

Trigger: Compiling a Wasm module whose conversion operator (in this arm: I64x2ExtendLow/HighI32x4S/U family, or a neighboring SIMD conversion like f32x4/f64x2 converts) reaches translate_conversion_operator but falls into the inner `_` arm via `Module::new` with the LLVM backend.

Common situations: Newer toolchains emitting SIMD conversion or relaxed-simd conversion instructions unsupported by the installed wasmer version; LLVM backend selected for SIMD modules; hand-modified or fuzzed bytecode bypassing validation.

Related errors


AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01). Data as JSON: /api/errors/81f6479937cfd285. Report an issue: GitHub.