{"record":{"id":"91a096f10067512b","repo":"wasmerio/wasmer","slug":"internal-error-origin-or-origin-in-runpath","errorCode":null,"errorMessage":"Internal error: $ORIGIN or ${{ORIGIN}} in RUNPATH, but no calling module path provided","messagePattern":"Internal error: \\$ORIGIN or (.+?)\\} in RUNPATH, but no calling module path provided","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/wasix/src/state/linker/locator.rs","lineNumber":99,"sourceCode":"            .as_ref()\n            .map(|p| p.as_ref().parent().unwrap_or_else(|| p.as_ref()));\n\n        let runtime_path = runtime_path.iter().map(|path| {\n            let path = path.as_ref();\n\n            let relative = path\n                .strip_prefix(\"$ORIGIN\")\n                .or_else(|| path.strip_prefix(\"${ORIGIN}\"));\n\n            match relative {\n                Some(relative) => {\n                    let Some(calling_module_dir) = calling_module_dir else {\n                        // This is an internal error because the only time calling_module_path\n                        // should be empty is when loading a module through dlopen, and a\n                        // dlopen'ed module isn't being required by another module so we don't\n                        // have a RUNPATH to consider at all. See the invocation of\n                        // `load_module_tree` in `load_module`.\n                        panic!(\n                            \"Internal error: $ORIGIN or ${{ORIGIN}} in RUNPATH, but \\\n                            no calling module path provided\"\n                        );\n                    };\n                    Cow::Owned(PathBuf::from(\n                        fs.relative_path_to_absolute(\n                            calling_module_dir\n                                .join(relative)\n                                .to_string_lossy()\n                                .into_owned(),\n                        ),\n                    ))\n                }\n                None => Cow::Borrowed(Path::new(path)),\n            }\n        });\n\n        // Search order is: LD_LIBRARY_PATH -> RUNPATH -> system default folders","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/wasix/src/state/linker/locator.rs#L81-L117","documentation":"locate_module expands $ORIGIN/${ORIGIN} in a RUNPATH to the directory of the calling module. If the RUNPATH contains $ORIGIN but no calling module path was provided, the code panics. The comment explains why: the only legitimate case of an empty calling_module_path is a top-level dlopen, and a dlopen'ed module has no RUNPATH-dependent requirer, so reaching this branch indicates a broken invariant in load_module_tree's invocation.","triggerScenarios":"load_module_tree invoked (via locate_module) to resolve a module whose RUNPATH entry contains $ORIGIN while calling_module_dir is None; a nested require chain where an intermediate module lost its path context.","commonSituations":"A .so's RUNPATH using $ORIGIN being loaded via plain dlopen rather than through the linker's module-tree loading path; a custom loader invocation passing no calling module path where RUNPATH resolution is needed; misbuilt shared library with $ORIGIN RUNPATH that should not be resolved relative to a requirer.","solutions":["Provide the calling module path when invoking load_module_tree so $ORIGIN can be expanded (see the load_module invocation site)","If loading via dlopen, avoid $ORIGIN in RUNPATH for top-level modules or pass the .so's own directory as the calling path","Rebuild the shared library to use an absolute RUNPATH if it is only ever dlopen'ed directly","If it occurs during a nested require, report it as a linker bug with the module dependency chain"],"exampleFix":"// before: dlopen'ing a module whose RUNPATH uses $ORIGIN, no calling path\nlet m = linker.load_module(\"/opt/app/libfoo.so\")?; // RUNPATH=$ORIGIN/../lib\n// after: pass the calling module path so $ORIGIN resolves\nlet m = linker.load_module_with_calling_path(\n    \"/opt/app/libfoo.so\",\n    Path::new(\"/opt/app/libfoo.so\"),\n)?;","handlingStrategy":"validation","validationCode":"fn runpath_needs_calling_path(runpath: &str) -> bool {\n    runpath.contains(\"$ORIGIN\") || runpath.contains(\"${ORIGIN}\")\n}\n// before loading: if runpath_needs_calling_path(&runpath) {\n//     ensure load_module_tree is invoked with Some(calling_module_path)\n// }","typeGuard":"fn has_calling_path(p: &Option<PathBuf>) -> bool {\n    p.as_ref().map_or(false, |p| !p.as_os_str().is_empty())\n}","tryCatchPattern":null,"preventionTips":["Pass the calling module path whenever a module's RUNPATH uses $ORIGIN","Avoid $ORIGIN in RUNPATH for modules loaded via plain dlopen","Prefer absolute RUNPATHs for top-level shared libraries","Test your module dependency chain for $ORIGIN usage before deploying"],"tags":["linker","runpath","dlopen","origin","panic"],"backgroundTag":"runpath-origin-unresolvable","analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}