config-rs: Cannot get config-rs to read env variables

Getting the following error when trying to get an environmental variable from config-rs:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: configuration property "DEV_SERVER_ADDRESS" not found', src/app/config.rs:14:27 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


use config::Config;
use lazy_static;

lazy_static! {
    #[derive(Debug)]
    pub static ref CONFIG: Config = Config::builder()
        .add_source(config::Environment::with_prefix("APP_NAME").separator("_"))
        .add_source(config::File::with_name("AppName"))
        .build()
        .unwrap();
}

pub fn get<'a, T: serde::Deserialize<'a>>(key: &str) -> T {
    CONFIG.get::<T>(&key).unwrap()
}

ENV variable:

export APP_NAME_DEV_SERVER_ADDRESS="testtt dev addr"

Trying to get the variable in main:

#[actix_web::main]
async fn main() -> result::Result<(), io::Error> {

    let dev_server_address: String = app::config::get("DEV_SERVER_ADDRESS");
    println!("DEV_SERVER_ADDRESS: {}", dev_server_address);
...

What am I doing wrong?

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 3
  • Comments: 16

Most upvoted comments

It will work as expected if used like this:

 .add_source(Environment::with_prefix("app").prefix_separator("__").separator("__"))

then APP__BRAINTREE__MERCHANT_ID will be correctly parsed to Braintree.merchant_id with snake_case setting name. Probably an example could be added to cover this case.

FWIW, I also cannot get this working with 0.13.2 and nested structs in my config.

When I use .add_source(config::Environment::with_prefix("TEST")) then I can successfully use environment variables like TEST_MYSTRUCT.MYFIELD

However, when I use .add_source(config::Environment::with_prefix("TEST").separator("_")), no environment variables seem to work at all:

  • TEST_MYSTRUCT.MYFIELD – no longer works, which is expected since the separator should be _
  • TEST_MYSTRUCT_MYFIELD – does not work, which is NOT expected

Something about separator(...) does not seem to behave as I would expect

It would be good to surface this in the docs, leaving a comment here so I remember to come back later and do this.

I just spent half an hour running a debugger getting to the bottom of this, only to realize that fundamentally _ as the separator while having _ in the variable names will never work, based on the approach in the code. I assumed that it was doing something like ‘for each variable in the config schema, check for an env-var’, which would be predictable and scale with the size of the schema. But instead it’s doing “check each envvar and if it matches the rules, try to insert it to the global config map”, without any schema-enriched info, which doesn’t work because _s get translated to .s. The approach taken also doesn’t seem to surface a warning anywhere when a close-but-not-quite envvar was set but is having no impact.

It may also be good to default the separator to __, since _ will be so common in struct field names.

What if for person.first_name you use a a dunderscore __ as the separator? Then you could write PERSON__FIRST_NAME and the replace would change it to PERSON.FIRST_NAME?

meh.

All this is really inconvenient. I hope I can make this better in the future with the rewrite I am planning.