wasmerio/wasmer · error
Cannot read non-scalar value from memory
Error message
Cannot read non-scalar value from memory
What it means
`read_value` in `call_dynamic` reconstructs `Value`s from linear memory by reading fixed-size byte slices. Reference types (ExternRef, FuncRef, ExceptionRef) have no byte-slice representation, so when the function's result/parameter type is a reference the code panics rather than producing an invalid value.
Source
Thrown at lib/wasix/src/syscalls/wasix/call_dynamic.rs:68
}
}};
}
fn read_value(
memory: &MemoryView,
offset: &mut u64,
max: u64,
strict: bool,
ty: &Type,
) -> Result<Option<Value>, MemoryAccessError> {
match ty {
Type::I32 => read_value!(memory, *offset, max, strict, i32, I32, 4),
Type::I64 => read_value!(memory, *offset, max, strict, i64, I64, 8),
Type::F32 => read_value!(memory, *offset, max, strict, f32, F32, 4),
Type::F64 => read_value!(memory, *offset, max, strict, f64, F64, 8),
Type::V128 => read_value!(memory, *offset, max, strict, u128, V128, 16),
// ExternRef, FuncRef, and ExceptionRef cannot be represented as byte slices
_ => panic!("Cannot read non-scalar value from memory"),
}
}
/// Call a function from the `__indirect_function_table` with parameters and results from memory.
///
/// This function can be used to call functions whose types are not known at
/// compile time of the caller. It is the callers responsibility to ensure
/// that the passed parameters and results match the signature of the function
/// being called.
///
/// ### Format of the values and results buffer
///
/// The buffers contain all values sequentially. i32, and f32 are 4 bytes,
/// i64 and f64 are 8 bytes, v128 is 16 bytes.
///
/// For example if the function takes an i32 and an i64, the values buffer will
/// be 12 bytes long, with the first 4 bytes being the i32 and the next 8
/// bytes being the i64.View on GitHub (pinned to 8c4b9ee9d3)
Solutions
- Only dynamically call functions whose results and parameters are scalar types; wrap ref-returning functions with a scalar adapter
- Return references via a host-managed side table (i32 handle) and read the handle from memory instead
- Pre-validate the callee's `Type` list before invoking `call_dynamic` and reject reference types with a proper error
- Use the regular (non-dynamic) call path for functions that traffic in reference types
Example fix
// before
type_results.iter().for_each(|t| read_value(memory, &mut off, max, strict, t)); // panics on Ref
// after
if type_results.iter().any(|t| matches!(t, Type::Ref(_))) {
return Err(Errno::Notsup);
} Defensive patterns
Strategy: validation
Validate before calling
// Ensure all result/param types are scalar before reading/writing memory
if type_results.iter().any(|t| matches!(t, Type::Ref(_)))
|| type_params.iter().any(|t| matches!(t, Type::Ref(_)))
{
return Err(Errno::Notsup);
} Type guard
fn all_scalar_types(types: &[Type]) -> bool {
types.iter().all(|t| matches!(t, Type::I32 | Type::I64 | Type::F32 | Type::F64 | Type::V128))
} Try / catch
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| read_value(memory, &mut off, max, strict, &ty)));
if result.is_err() { /* ref result: resolve via side table or return Notsup */ } Prevention
- Filter ref-typed functions out of the indirect function table used by call_dynamic
- Return references via host-managed handles, not raw memory
- Assert all_scalar_types on callee signatures in debug builds
- Compile guests with reference-types disabled when using dynamic calls
When it happens
Trigger: Calling a function via `call_dynamic` whose signature declares a reference-typed result or parameter; reading results back from memory after an indirect call when the callee returns externref/funcref/exceptionref.
Common situations: Modules compiled with reference-types enabled being invoked through the WASIX dynamic closure mechanism; type confusion where the indirect-function-table slot type changed but the caller's scalar-only expectations did not; generated stubs that don't filter ref types.
Related errors
- Cannot write non-scalar value as bytes
- Cannot get size of reference type
- Cannot store reference type
- Failed to free closure index: {e}
- Cannot load reference type
AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01).
Data as JSON: /api/errors/ff258005cc36b8e3.
Report an issue: GitHub.