{"record":{"id":"925d3720672c837c","repo":"apache/shenyu","slug":"wasi-proc-exit-exitcode-from-wasmname","errorCode":null,"errorMessage":"WASI proc_exit(${exitCode}) from ${wasmName}","messagePattern":"WASI proc_exit\\((.+?)\\) from (.+?)","errorType":"exception","errorClass":"ShenyuWasmException","httpStatus":null,"severity":"error","filePath":"shenyu-plugin/shenyu-plugin-wasm-api/src/main/java/org/apache/shenyu/plugin/wasm/api/loader/WasmLoader.java","lineNumber":181,"sourceCode":"        var options = com.dylibso.chicory.wasi.WasiOptions.builder()\n                .withStdout(System.out)\n                .withStderr(System.err)\n                .build();\n        var wasi = com.dylibso.chicory.wasi.WasiPreview1.builder()\n                .withOptions(options)\n                .build();\n        store.addFunction(wasi.toHostFunctions());\n\n        // Override proc_exit with a no-op: valid WASI program exit (proc_exit(0))\n        // is normal termination and should not propagate as a Java exception in\n        // a hosted plugin runtime.\n        store.addFunction(new HostFunction(\n                \"wasi_snapshot_preview1\", \"proc_exit\",\n                FunctionType.of(List.of(ValType.I32), List.of()),\n                (inst, args) -> {\n                    int exitCode = (int) args[0];\n                    if (exitCode != 0) {\n                        throw new ShenyuWasmException(\"WASI proc_exit(\" + exitCode + \") from \" + wasmName);\n                    }\n                    return new long[0];\n                }\n        ));\n    }\n\n    private void registerBuiltinHostFunctions(final Store store) {\n        store.addFunction(new HostFunction(\n                IMPORT_WASM_MODULE_NAME, \"get_args\",\n                FunctionType.of(List.of(ValType.I64, ValType.I64, ValType.I32), List.of(ValType.I32)),\n                (instance, args) -> new long[]{onGetArgs(args[0], args[1], (int) args[2])}\n        ));\n        store.addFunction(new HostFunction(\n                IMPORT_WASM_MODULE_NAME, \"put_result\",\n                FunctionType.of(List.of(ValType.I64, ValType.I64, ValType.I32), List.of(ValType.I32)),\n                (instance, args) -> new long[]{onPutResult(args[0], args[1], (int) args[2])}\n        ));\n    }","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-plugin/shenyu-plugin-wasm-api/src/main/java/org/apache/shenyu/plugin/wasm/api/loader/WasmLoader.java#L163-L199","documentation":"WasmLoader registers a WASI proc_exit host stub; when the wasm module calls proc_exit with a non-zero exit code — the module's equivalent of exiting with failure — the stub throws ShenyuWasmException carrying the exit code and module name. This surfaces a deliberate abort inside the wasm program rather than a gateway fault, and only for exitCode == 0 is the call treated as success.","triggerScenarios":"Executing an exported wasm function that internally calls wasi_snapshot_preview1.proc_exit with a non-zero argument, e.g. after hitting an unrecoverable condition (assertion failure, missing WASI resource, aborted computation) inside the module.","commonSituations":"wasm modules compiled with WASI support aborting on panics (Rust panic=abort calls proc_exit(1)); modules calling exit() on error paths; wasm code failing on unexpected input and terminating itself.","solutions":["Inspect the wasm module's logic (or its source) for the code path calling proc_exit/exit and fix the underlying condition that triggers the non-zero exit.","Catch ShenyuWasmException around the plugin's invoke call and map it to an appropriate gateway error response for clients.","Validate inputs to the wasm function before invoking to avoid the module's error/abort path.","Rebuild the module with panic handlers that return error codes through memory instead of calling proc_exit."],"exampleFix":"// before (wasm side)\nif (bad_input) { proc_exit(1); }\n// after\nif (bad_input) { set_err_code(ERR_BAD_INPUT); return; }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    Object result = wasmLoader.invoke(...);\n} catch (ShenyuWasmException e) {\n    if (e.getMessage().startsWith(\"WASI proc_exit(\")) {\n        // map module abort to gateway error response\n        return WebFluxResultUtils.failedResult(...);\n    }\n    throw e;\n}","preventionTips":["Fix wasm code to return error codes via memory instead of calling proc_exit on failure paths.","Validate inputs before invoking wasm functions.","Compile wasm with panic handlers (e.g. Rust panic=unwind with catch_unwind) rather than abort->proc_exit."],"tags":["wasm","wasi","proc-exit","runtime"],"backgroundTag":"wasm-proc-exit-nonzero","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}