apache/shenyu · error · ShenyuWasmInitException

Can't find wasm file

Error message

Can't find wasm file: ${wasmName}

What it means

WasmLoader locates the '.wasm' binary as a classpath resource named after the fully-qualified class name (ClassName + '.wasm') via clazz.getClassLoader().getResource(). If no such resource is on the classpath it throws ShenyuWasmInitException at construction time, because the WebAssembly module cannot be instantiated at all.

Solutions

  1. Ensure the .wasm file lives under src/main/resources with a path matching the Java class's package and the exact class simple name, e.g. org/apache/shenyu/plugin/xxx/MyPlugin.wasm for class org.apache.shenyu.plugin.xxx.MyPlugin.
  2. Rebuild the module so the .wasm is copied into target/classes and packaged into the jar.
  3. Check Maven build config (resource excludes/filtering) is not stripping .wasm files; add them to <resources> if needed.
  4. If you renamed the class, rename the .wasm file (or pass the correct wasmClass reference) to keep them in sync.

Example fix

// before: class org.apache.shenyu.plugin.ai.FooPlugin, resource at resources/foo.wasm
// after
src/main/resources/org/apache/shenyu/plugin/ai/FooPlugin.wasm
Defensive patterns

Strategy: validation

Validate before calling

String resource = MyClass.class.getName().replace('.', '/') + ".wasm";
if (MyClass.class.getClassLoader().getResource(resource) == null) {
    throw new IllegalStateException("wasm resource missing from classpath: " + resource);
}

Try / catch

try {
    WasmLoader loader = new MyWasmPlugin();
} catch (ShenyuWasmInitException e) {
    if (e.getMessage().startsWith("Can't find wasm file")) { /* fix packaging/renaming */ }
    throw e;
}

Prevention

When it happens

Trigger: Constructing a WasmLoader (or subclass plugin) when the .wasm file was not packaged next to the class: the file name does not equal the fully-qualified class name + '.wasm', or the resource was excluded from the jar/target classes.

Common situations: Renaming a Java class without renaming the accompanying .wasm file (or vice versa); Maven resource filtering/excludes dropping .wasm files from the jar; building a custom plugin and forgetting to place the compiled .wasm under src/main/resources with the matching package path.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/3c2905bf425186f9. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-plugin/shenyu-plugin-wasm-api/src/main/java/org/apache/shenyu/plugin/wasm/api/loader/WasmLoader.java:90

     * <ol>
     *   <li>Register full WASI preview1 functions via Chicory's built-in implementation</li>
     *   <li>If {@code initializer} is non-null, call it; otherwise register built-in host functions
     *       ({@code get_args}/{@code put_result}) and call {@link #initWasmCallJavaFunc(Store)}</li>
     * </ol>
     *
     * @param wasmClass   the class whose name determines the .wasm resource path; if null, uses
     *                    {@code this.getClass()} (inheritance mode)
     * @param initializer optional consumer to register host functions; when non-null the built-in
     *                    host functions and {@link #initWasmCallJavaFunc(Store)} are skipped
     */
    public WasmLoader(final Class<?> wasmClass, final Consumer<Store> initializer) {
        final Class<?> clazz = Objects.nonNull(wasmClass) ? wasmClass : this.getClass();
        this.wasmName = clazz.getName() + ".wasm";
        try {
            // locate `.wasm` lib.
            URL resource = clazz.getClassLoader().getResource(wasmName);
            if (Objects.isNull(resource)) {
                throw new ShenyuWasmInitException("Can't find wasm file: " + wasmName);
            }
            // Instantiates the WebAssembly module.

            this.store = new Store();

            // Register WASI preview1 functions via Chicory's built-in implementation,
            // then override proc_exit with a no-op to avoid WasiExitException.
            registerWasiStubs(store);

            // Allow subclasses to register custom host functions (get_args/put_result).
            if (Objects.nonNull(initializer)) {
                initializer.accept(store);
            } else {
                registerBuiltinHostFunctions(store);
            }

            // Allow WasmLoader subclasses to override and register additional host functions.
            // Only called when not using Consumer initializer, to avoid double invocation.

View on GitHub (pinned to 567142e072)