config-rs icon indicating copy to clipboard operation
config-rs copied to clipboard

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

Open gabrielkim13 opened this issue 1 year ago • 4 comments
trafficstars

Starting at [email protected], 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 [email protected] 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!",
} 

gabrielkim13 avatar Feb 02 '24 16:02 gabrielkim13

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

matthiasbeyer avatar Feb 02 '24 18:02 matthiasbeyer

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

gabrielkim13 avatar Feb 02 '24 18:02 gabrielkim13

Same bug I believe: https://github.com/mehcode/config-rs/issues/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.

polarathene avatar Feb 03 '24 21:02 polarathene

I've encountered the same issue. When using [email protected] 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.

Lawson-Y avatar Apr 10 '24 07:04 Lawson-Y