{"record":{"id":"0e84c388f2765cda","repo":"wasmerio/wasmer","slug":"internal-error-failed-to-resolve-exported-functio","errorCode":null,"errorMessage":"Internal error: failed to resolve exported function {}: {e:?}","messagePattern":"Internal error: failed to resolve exported function (.+?): (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"lib/wasix/src/state/linker/instance_group.rs","lineNumber":328,"sourceCode":"                .map(|v| v as u64);\n\n        self.complete_side_module_from_linker(prepared, tls_base, store)\n    }\n\n    pub(super) fn finalize_pending_resolutions_from_linker(\n        &self,\n        pending_resolutions: &PendingResolutionsFromLinker,\n        store: &mut impl AsStoreMut,\n    ) -> Result<(), LinkError> {\n        trace!(\"Finalizing pending functions\");\n\n        for pending in &pending_resolutions.functions {\n            let func = self\n                .instance(pending.resolved_from)\n                .exports\n                .get_function(&pending.name)\n                .unwrap_or_else(|e| {\n                    panic!(\n                        \"Internal error: failed to resolve exported function {}: {e:?}\",\n                        pending.name\n                    )\n                });\n\n            self.place_in_function_table_at(store, func.clone(), pending.function_table_index)\n                .map_err(LinkError::TableAllocationError)?;\n\n            trace!(?pending, \"Placed pending function in table\");\n        }\n\n        for tls in &pending_resolutions.tls {\n            let Some(tls_base) = self.tls_base(tls.resolved_from) else {\n                // This is a panic since this error should have been caught when the symbol\n                // was originally resolved by the instigating instance group. We're just replaying\n                // the changes.\n                panic!(\n                    \"Internal error: Tried to import TLS symbol from module {} that \\","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/wasix/src/state/linker/instance_group.rs#L310-L346","documentation":"During dynamic linking of side modules, finalize_pending_resolutions_from_linker replays earlier linker resolutions: it fetches a function that was previously resolved from the exporting instance's exports. If get_function now fails, the replay diverged from the original resolution, indicating an internal state-consistency bug, so the code panics.","triggerScenarios":"Calling apply_dl_operation / instantiate_side_module_from_link_state where a pending function resolution references an instance whose exports no longer contain `pending.name` — e.g. link_state mutated between symbol resolution and finalization, wrong instance index (resolved_from), or exports dropped/overridden before finalization.","commonSituations":"Custom dlopen-style dynamic linking flows in lib/wasix; buggy use of internal InstanceGroup APIs in forks/experiments; wasmtime version mismatch between code building the link state and the code replaying it.","solutions":["Verify the pending resolution's `resolved_from` instance index is the actual exporting instance recorded during link-state building.","Ensure the link_state is not mutated or partially applied between resolution and finalize_pending_resolutions_from_linker.","Update wasmtime/wasix — if this fires on normal dlopen flows it is an upstream bug; reproduce and report with the module pair involved.","If you fork the linker, add logging of link_state.symbols at resolution time to find where the export disappeared."],"exampleFix":"// before (state mutated between phases, resolution replays stale index)\nlet func = self.instance(pending.resolved_from).exports.get_function(&pending.name);\n// after: re-resolve against the current link state instead of replaying blindly\nlet func = self.instance(current_resolution.resolved_from)\n    .exports.get_function(&current_resolution.name)\n    .expect(\"resolution recorded in link_state must exist at finalize time\");","handlingStrategy":"validation","validationCode":"// Before finalizing, verify every pending resolution still exists\nfor pending in &pending_resolutions.functions {\n    let inst = group.instance(pending.resolved_from);\n    assert!(inst.exports.get_function(&pending.name).is_ok(),\n        \"pending function {} missing from instance exports before finalize\", pending.name);\n}","typeGuard":null,"tryCatchPattern":"// Internal panic; isolate at a thread boundary in custom dlopen flows:\nlet result = std::panic::catch_unwind(|| group.apply_dl_operation(&op));\nmatch result {\n    Ok(r) => r,\n    Err(_) => return Err(LinkError::InternalResolutionReplayFailed),\n}","preventionTips":["Never mutate link_state or instance exports between symbol resolution and finalization.","Keep resolved_from indices stable; do not reorder instance creation mid-link.","Use stock wasmtime dlopen flows rather than hand-editing pending resolutions.","Keep wasmtime versions consistent across your build."],"tags":["panic","dynamic-linking","wasix","internal-error"],"backgroundTag":"dynamic-linking-resolution-mismatch","analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}