Path extractor fails when routes are loaded from a dynamic library (but Json extractor works)
Triment opened this issue · comments
- I have looked for existing issues (including closed) about this
Bug Report
Version
axum v0.8.4
Platform
Darwin asdeMac-Pro.lan 24.4.0 Darwin Kernel Version 24.4.0: Fri Apr 11 18:28:23 PDT 2025; root:xnu-11417.101.15~117/RELEASE_X86_64 x86_64
Description
Hi, I’m encountering a strange issue with Axum 0.8 when using dynamic libraries (plugins), Loading by libloading = "0.8.8"
.
In the main program, path parameter extraction works as expected.
When I load routes from a dynamic library (compiled separately), Path extractor fails with the error:
No paths parameters found for matched route
//In the plugin
Router::new()
//.route("/", axum::routing::get(home))
.route("/assets/{*path}", axum::routing::get(async |req: Request| { //It's working
let path = req.uri().path();
format!("assets/{}", path)
}))
Router::new()
//.route("/", axum::routing::get(home))
.route("/assets/{*path}", axum::routing::get(async|Path(path): Path<String>|{ //throw error
path
}))
Router::new()
//.route("/", axum::routing::get(home))
.route("/assets/{*path}", axum::routing::post(async |Json(HelloRequest { name }): Json<HelloRequest>| {// It's working
format!("hello {}", name)
}))
Main program code
let plugin = plugin_loader::load_plugins()?;//Dynamic libraries
let plugin_routes = plugin.routes();
app = app.nest("/plugins/hello/", plugin_routes);
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;
let server = axum::serve(listener, app).with_graceful_shutdown(async move {
shutdown_recv.recv().await;
});
I'm sorry, but what you are doing is not supported by Rust. You can't compile two binaries / shared libraries independently (even with the same compiler version) and use "regular" Rust types / code across that boundary¹. It has nothing to do with axum really, except that axum happens to rely on a type-map for path arguments which probably trips up your code because the type-id of the thing we store / read internally is different within your plugin and main binary.
¹ you would have to make sure to constrain yourself to #[repr(C)]
types, for globals used by both it's complicated and for type-id I don't know if there is any solution other than avoiding it completely