mehcode/config-rs

bug: Using the `serde` attribute `rename` fails since `0.14.0` with a `missing field` error

Opened this issue · 4 comments

Starting at config@0.14.0, serde renamed fields are no longer supported due to the "missing field" error.


Consider the following minimal reproduceable example:

# Cargo.toml

[package]
name = "config-missing-field"
version = "0.1.0"
edition = "2021"

[dependencies]
config = { version = "0.14", default-features = false, features = ["json"] }
serde = { version = "1", features = ["derive"] }
// main.rs

use config::{Config, File, FileFormat};

#[allow(unused)]
#[derive(serde::Deserialize, Debug)]
struct MyConfig {
    #[serde(rename = "FooBar")]
    foo_bar: String,
}

fn main() {
    const MY_CONFIG: &str = r#"{
        "FooBar": "Hello, world!"
    }"#;

    let cfg = Config::builder()
        .add_source(File::from_str(MY_CONFIG, FileFormat::Json))
        .build()
        .unwrap();

    println!("{cfg:#?}");

    let my_config: MyConfig = cfg.try_deserialize().unwrap();

    // Panics at the previous instruction, with "missing field" error.

    println!("{my_config:#?}");
}

The output is as follows:

❯ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/config-missing-field`
Config {
    defaults: {},
    overrides: {},
    sources: [],
    cache: Value {
        origin: None,
        kind: Table(
            {
                "foobar": Value {
                    origin: None,
                    kind: String(
                        "Hello, world!",
                    ),
                },
            },
        ),
    },
}
thread 'main' panicked at src/main.rs:27:53:
called `Result::unwrap()` on an `Err` value: missing field `FooBar`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace 

Reverting the dependency back to config@0.13.4 works as expected:

❯ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/config-missing-field`
Config {
    defaults: {},
    overrides: {},
    sources: [],
    cache: Value {
        origin: None,
        kind: Table(
            {
                "FooBar": Value {
                    origin: None,
                    kind: String(
                        "Hello, world!",
                    ),
                },
            },
        ),
    },
}
MyConfig {
    foo_bar: "Hello, world!",
} 

Thanks for filing this!
Awesome (irony) that our tests did not find this 😢

You're welcome! And thanks for the quick response :)

Same bug I believe: #531

rename should work presumably if only using lowercase value? Looks like 0.14.0 has some fixes contributed that converted to lowercase that broke serde features.

I've encountered the same issue. When using config@0.14 in combination with serde, applying #[serde(rename_all = "camelCase")] to handle the yaml configuration file does not work as expected. Below is the configuration file:

dataBase:
  url: "http://www.ss.com.cn"
  userName: "张三"
  password: "1233"
addr: "0.0.0.0:8887"
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Conf {
    pub data_base: Option<DataBase>,
    pub addr: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct DataBase {
    pub url: String,
    pub user_name: String,
    pub password: String,
    #[serde(default)]
    pub data_base_connection_poll: DataBaseConnectionPool,
}

When I reverted the config to version 0.13, this code executed as expected.