wasmerio/wasmer · error · anyhow::Error

The headless engine can't be chosen

Error message

The headless engine can't be chosen

What it means

BackendType::Headless is a placeholder meaning "no compiler, deserialize precompiled artifacts"; it is not a compiler that get_sys_compiler_config can produce a CompilerConfig for. Any attempt to fetch a compiler config for the headless backend bails immediately.

Source

Thrown at lib/cli/src/backend.rs:439

        let compiler_config = self.get_sys_compiler_config(backends.first().unwrap())?;
        let default_features = compiler_config.default_features_for_target(&target);
        let features = self.get_features(&default_features)?;
        Ok(wasmer_compiler::EngineBuilder::new(compiler_config)
            .set_features(Some(features))
            .set_target(Some(target))
            .engine()
            .into())
    }

    #[allow(unused_variables)]
    #[cfg(feature = "compiler")]
    pub(crate) fn get_sys_compiler_config(
        &self,
        rt: &BackendType,
    ) -> Result<Box<dyn CompilerConfig>> {
        self.validate_profiler()?;
        let compiler_config: Box<dyn CompilerConfig> = match rt {
            BackendType::Headless => bail!("The headless engine can't be chosen"),
            #[cfg(feature = "singlepass")]
            BackendType::Singlepass => {
                let mut config = wasmer_compiler_singlepass::Singlepass::new();
                if self.enable_experimental_unaligned_memory_accesses {
                    config.allow_experimental_unaligned_memory_accesses(true);
                }
                if self.enable_verifier {
                    config.enable_verifier();
                }
                if self.enable_nan_canonicalization {
                    config.canonicalize_nans(true);
                }
                if let Some(p) = &self.profiler {
                    match p {
                        Profiler::Perfmap => config.enable_perfmap(),
                        Profiler::Gdb => config.enable_debugger(Debugger::Gdb),
                        Profiler::Lldb => config.enable_debugger(Debugger::Lldb),
                    }

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Use a compiling backend (cranelift, singlepass, or llvm) instead of headless for compilation paths
  2. Only use the headless engine with precompiled .wasmu artifacts
  3. Fix the default backend/engine selection in your configuration or launcher

Example fix

// before
let engine = get_engine(&BackendType::Headless, target, &opts)?;
// after
let engine = get_engine(&BackendType::Cranelift, target, &opts)?;
Defensive patterns

Strategy: validation

Validate before calling

if matches!(rt, BackendType::Headless) {
    return Err("headless cannot compile; use cranelift/singlepass/llvm for compilation paths");
}

Type guard

fn is_compilable(rt: &BackendType) -> bool {
    !matches!(rt, BackendType::Headless | BackendType::V8)
}

Try / catch

match result {
    Err(e) if e.to_string().contains("headless engine can't be chosen") => {
        retry_with_backend(BackendType::Cranelift)
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling get_sys_compiler_config(rt) with rt == BackendType::Headless, typically via get_sys_compiler_engine_for_target when the chosen engine type is Headless.

Common situations: Passing --engine headless to a command that needs to compile (not just deserialize) a module; programmatically selecting the headless backend where a JIT engine is required; misconfigured runtime defaulting to headless.

Related errors


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