{"record":{"id":"29f7d6f897c03275","repo":"wasmerio/wasmer","slug":"function-call-async-futures-cannot-be-polled-recu","errorCode":null,"errorMessage":"Function::call_async futures cannot be polled recursively from within another imported function. If you need to await a recursive call_async, consider spawning the future into your async runtime and awaiting the resulting task; e.g. tokio::task::spawn(func.call_async(...)).await","messagePattern":"Function::call_async futures cannot be polled recursively from within another imported function\\. If you need to await a recursive call_async, consider spawning the future into your async runtime and awaiting the resulting task; e\\.g\\. tokio::task::spawn\\(func\\.call_async\\(\\.\\.\\.\\)\\)\\.await","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/api/src/backend/sys/async_runtime.rs","lineNumber":266,"sourceCode":"            // We always need to acquire a new write lock on the store.\n            let store_guard = store.inner.write().await;\n            unsafe { crate::StoreContext::install_async(store_guard) }\n        }\n        _ => {\n            // If we're already in a store context, it is unsafe to reuse\n            // the existing store ref since it'll also be accessible from\n            // the imported function that tried to poll us, which is a\n            // double mutable borrow.\n            // Note to people who discover this code: this *would* be safe\n            // if we had a separate variation of call_async that just\n            // used the existing coroutine context instead of spawning a\n            // new coroutine. However, the current call_async always spawns\n            // a new coroutine, so we can't allow this; every coroutine\n            // needs to own its write lock on the store to make sure there\n            // are no overlapping mutable borrows. If this is something\n            // you're interested in, feel free to open a GitHub issue outlining\n            // your use-case.\n            panic!(\n                \"Function::call_async futures cannot be polled recursively \\\n                from within another imported function. If you need to await \\\n                a recursive call_async, consider spawning the future into \\\n                your async runtime and awaiting the resulting task; \\\n                e.g. tokio::task::spawn(func.call_async(...)).await\"\n            );\n        }\n    }\n}\n\npub enum AsyncRuntimeError {\n    YieldOutsideAsyncContext,\n    RuntimeError(RuntimeError),\n}\n\npub(crate) fn block_on_host_future<Fut>(future: Fut) -> Result<Vec<Value>, AsyncRuntimeError>\nwhere\n    Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/api/src/backend/sys/async_runtime.rs#L248-L284","documentation":"Error \"Function::call_async futures cannot be polled recursively from within another imported function. If you need to await a recursive call_async, consider spawning the future into your async runtime and awaiting the resulting task; e.g. tokio::task::spawn(func.call_async(...)).await\" thrown in wasmerio/wasmer.","triggerScenarios":"Thrown at lib/api/src/backend/sys/async_runtime.rs:266 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":[],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}