rust-lang/rust · critical

can't link as reactor on non-wasi target

Error message

can't link as reactor on non-wasi target

What it means

Thrown by the MSVC linker's set_output_kind when it receives a LinkOutputKind::WasiReactorExe. The MSVC linker only knows how to produce Windows executables, DLLs, and their import libraries; a WASI reactor executable is a WebAssembly concept with no MSVC representation, so reaching this arm means the chosen linker does not match the requested output kind. It signals a fundamentally inconsistent target configuration.

Source

Thrown at compiler/rustc_codegen_ssa/src/back/linker.rs:969

    fn set_output_kind(
        &mut self,
        output_kind: LinkOutputKind,
        _crate_type: CrateType,
        out_filename: &Path,
    ) {
        match output_kind {
            LinkOutputKind::DynamicNoPicExe
            | LinkOutputKind::DynamicPicExe
            | LinkOutputKind::StaticNoPicExe
            | LinkOutputKind::StaticPicExe => {}
            LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
                self.link_arg("/DLL");
                let mut arg: OsString = "/IMPLIB:".into();
                arg.push(out_filename.with_extension("dll.lib"));
                self.link_arg(arg);
            }
            LinkOutputKind::WasiReactorExe => {
                panic!("can't link as reactor on non-wasi target");
            }
        }
    }

    fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
        // On MSVC-like targets rustc supports import libraries using alternative naming
        // scheme (`libfoo.a`) unsupported by linker, search for such libraries manually.
        if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) {
            self.link_arg(path);
        } else {
            self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
        }
    }

    fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
        // When producing a dll, MSVC linker may not emit an implib file if the dll doesn't export
        // any symbols, so we skip linking if the implib file is not present.
        let implib_path = path.with_extension("dll.lib");

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Target an actual WASI triple such as wasm32-wasip1 or wasm32-wasip2 and let rustc select the wasm linker.
  2. Verify -C linker-flavor and the target spec's linker flavor are not set to a Windows/MSVC flavor for a wasm/reactor build.
  3. Remove reactor-specific options (e.g. -C link-arg=--export=...) unless targeting wasm32-wasi with a wasm-compatible linker.
Defensive patterns

Strategy: validation

Validate before calling

fn reactor_target_ok(target: &str) -> bool {
    target.contains("wasi")
}

// caller: if cfg!(feature = "reactor") { assert!(reactor_target_ok(&target)); }

Type guard

fn is_wasi_reactor_capable(target: &str) -> bool {
    target.starts_with("wasm32-wasi") || target.starts_with("wasm32-wasip1")
        || target.starts_with("wasm32-wasip2") || target.starts_with("wasm32-wasi-preview2")
}

Try / catch

let stderr = String::from_utf8_lossy(&output.stderr);
if stderr.contains("can't link as reactor on non-wasi target") {
    return Err(LinkError::ReactorRequiresWasi { actual_target: target.into() });
}

Prevention

When it happens

Trigger: Produced when crate-type/output configuration requests a WASI reactor executable (e.g. -C link-arg or target spec selecting reactor) but the linker selected for the job is the MSVC linker. Usually the result of a target spec or -C linker-flavor mismatch mixing wasm output flags with an msvc toolchain.

Common situations: A custom or hand-edited target JSON that combines WASI-ish options with an msvc linker flavor. Forcing -C linker-flavor incorrectly. A misconfigured xwin/cross environment routing a wasm build through the Windows linker.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/98d087bef2e85401.json. Report an issue: GitHub.