unexpected cfg condition value: server
主线位置:调用主线的起点。
#[post]展开出的服务端一半包在#[cfg(feature = "server")]里,inventory::submit!登记也在里面(见 server function)。这个cfg求值时看的是你的 crate 的 feature,不是 dioxus 的,所以 Cargo.toml 写错一处,要么编不过,要么路由表里少了这条路由。
flowchart TB
macro["#[post] 展开"] --> cfgq{"crate 声明了 server"}
cfgq -->|没有| e1["编译错误 unexpected cfg"]
cfgq -->|声明了| onq{"这次编译打开了吗"}
onq -->|没有| e2["不登记 POST 得 405"]
onq -->|打开| reg["Registering POST /api/double"]
本页的实验 crate 都是 dioxus = "=0.7.10",M2 Max、macOS 27、rustc 1.99.0,cargo build --offline 直接编(不经过 dx),最后一节用 dx 0.7.9。
现象
一:没声明 server feature
依赖里已经打开了 dioxus 的 server,但 crate 自己没有 [features] 段(pit2-nofeat):
[dependencies]
dioxus = { version = "=0.7.10", features = ["fullstack", "server"] }
use dioxus::prelude::*;
#[post("/api/double")]
async fn double(n: i32) -> Result<i32, ServerFnError> {
Ok(n * 2)
}
fn main() {
let _ = double;
}
cargo build 的输出:
error: unexpected `cfg` condition value: `server`
--> src/main.rs:3:1
|
3 | #[post("/api/double")]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: no expected values for `feature`
= note: using a cfg inside a attribute macro will use the cfgs from the destination crate and not the ones from the defining crate
= help: try referring to `post` crate for guidance on how handle this unexpected cfg
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
= note:
==========================================================================================
Using Dioxus Server Functions requires a `server` feature flag in your `Cargo.toml`.
Please add the following to your `Cargo.toml`:
```toml
[features]
server = ["dioxus/server"]
```
To enable better Rust-Analyzer support, you can make `server` a default feature:
```toml
[features]
default = ["web", "server"]
web = ["dioxus/web"]
server = ["dioxus/server"]
```
==========================================================================================
note: the lint level is defined here
--> src/main.rs:3:1
|
3 | #[post("/api/double")]
| ^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the attribute macro `post` (in Nightly builds, run with -Z macro-backtrace for more info)
error: could not compile `pit2-nofeat` (bin "pit2-nofeat") due to 1 previous error
unexpected_cfgs 平时只是警告,这里是错误,因为宏在生成的函数上加了 #[deny(unexpected_cfgs)]。
二:声明了,但这次编译没打开
pit2-halffeat 加上了 [features] server = ["dioxus/server"],其他不变,main 里 dioxus::launch(app)。依赖的 dioxus/server 一直开着,所以 cargo build(不带 --features)编出来的仍然是一个能启动的服务端。先在可执行文件旁边建一个空的 public/(原因见第三种),IP=127.0.0.1 PORT=18820 启动,再 curl -X POST /api/double -d '{"n":21}':
== cargo build (no --features)
2026-10-28T12:35:28.450491Z WARN dioxus_server::config: No index.html found in public directory, using default index.html
HTTP/1.1 405 Method Not Allowed
allow: GET,HEAD
content-length: 0
== cargo build --features server
2026-10-28T12:35:33.407069Z WARN dioxus_server::config: No index.html found in public directory, using default index.html
2026-10-28T12:35:33.412828Z INFO dioxus_server::server: Registering: POST /api/double
HTTP/1.1 200 OK
content-type: application/json
content-length: 2
42
没打开时编译、启动都没有任何提示,只是少了那行 Registering。请求落进渲染页面的 fallback,fallback 只接 GET,所以是 405,Allow: GET,HEAD。浏览器里的 server function 调用得到的就是这个 405。
三:cargo 编的服务端旁边没有 public/
同一个二进制,删掉 public/ 再启动:
2026-10-28T12:35:16.639321Z WARN dioxus_server::config: No index.html found in public directory, using default index.html
thread 'main' (2208197) panicked at ~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/dioxus-server-0.7.10/src/server.rs:409:29:
Couldn't read public directory at "~/exp-dioxus/target-pit2/debug/public": No such file or directory (os error 2)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
缺 index.html 只是一条警告(换成不带 wasm 的最小模板),缺整个目录是 panic。
四:dx 和 dioxus 版本不一致
用 dx 0.7.9 构建依赖 dioxus 0.7.10 的应用,日志开头:
0.00s INFO Building project...
0.54s ERROR 🚫dx and dioxus versions are incompatible!
• dx version: 0.7.9
• dioxus versions: [0.7.10]
2.09s INFO Compiled [ 1/305]: cfg_if
之后照常编完(Client build completed successfully!),本卷所有实验都是这样构建的。这一行只是提示,不中止构建。
出处
- 编译错误:
route_impl_with_route生成服务端那一半时,在函数上加#[deny(unexpected_cfgs, reason = "...")],reason就是上面那一大段说明。宏展开出的#[cfg(feature = "server")]在用户 crate 里求值,Cargo 只把 crate 自己声明过的 feature 名告诉 rustc 的 check-cfg,没声明就是「no expected values forfeature」。 - 405:服务端一半和
inventory::submit!都在这个cfg后面。feature 没开,这个函数在二进制里只剩客户端一半,register_server_functions遍历inventory时根本看不到它。fallback 是get(render_handler)(一次请求的渲染)。 public/:public_path没有DIOXUS_PUBLIC_PATH时取「可执行文件所在目录/public」,serve_dir_cached对它read_dir,失败就panic!("Couldn't read public directory at ...")。dx build会把public/放在server旁边,cargo 不会。- 版本:dx 的
check_dioxus_version_against_cli在工作区里所有dioxus版本的最小值大于 dx、最大值小于 dx、或预发布标记不同时tracing::error!,然后返回,构建继续。补丁号差一位也会触发。
修法
Cargo.toml 照报错里的说明写,客户端和服务端各一个 feature,dioxus 本身不直接开 server / web:
[dependencies]
dioxus = { version = "=0.7.10", features = ["router", "fullstack"] }
[features]
default = []
web = ["dioxus/web"]
server = ["dioxus/server"]
dx build --platform web --fullstack 编客户端时打开 web、编服务端时打开 server,本卷的 pit2-fs 就是这份配置,服务端日志里每个函数都有一行 Registering。只用 cargo 编服务端时要 --features server,并且把 dx 产出的 public/ 放到可执行文件旁边,或者用 DIOXUS_PUBLIC_PATH 指过去。
只在服务端用到的依赖(数据库、tokio 的额外 feature)挂在 server 下面做成可选依赖,函数体里用到它们的代码放在 #[cfg(feature = "server")] 里,否则客户端那次编译会把它们编进 wasm 或者编不过。
版本那一行:把 dx 和 dioxus 对齐到同一个补丁版本,或者确认两者之间只差 CLI 的改动。本卷的情况是后者:0.7.9 到 0.7.10 只改了 packages/cli/(见卷首)。
怎么确认没中招
- 服务端启动日志里,每个 server function 一行
INFO dioxus_server::server: Registering: <方法> <路径>。数一下和代码里的#[post]/#[get]/#[server]个数对不对得上。 - 部署后对每个函数发一次正确方法的请求:405 带
Allow: GET,HEAD就是没登记(登记了的路由方法不对时,Allow是它自己的方法,比如POST)。 - 容器里跑
ls "$(dirname "$(readlink -f ./server)")/public",或者在启动脚本里设DIOXUS_PUBLIC_PATH。 - CI 里把
dx --version和cargo tree -i dioxus --depth 0的输出比一下,不一致就失败,不靠那一行 ERROR。
小结
#[post]生成的cfg(feature = "server")看的是你的 crate;没声明server是#[deny(unexpected_cfgs)]的编译错误,报错里附了正确的 Cargo.toml。- 声明了但这次编译没打开:服务端照常启动,函数不登记,POST 得 405,没有任何警告。认准启动日志里的
Registering行。 - cargo 直接编的服务端要自己准备
public/,否则server.rs:409panic。 - dx 与 dioxus 版本不一致只打一行 ERROR,构建继续。