valeriansaliou/sonic · critical · panic

error reading config

Error message

error reading config

What it means

sonic-server's Config::parse builds a figment/config value from file sources plus SONIC_-prefixed environment variables and calls .expect("error reading config"). This panics when the config crate cannot even load/assemble the raw configuration — before any deserialization — typically because a configured file is missing/unreadable or an environment source is malformed.

Source

Thrown at server/src/config.rs:85

impl Config {
    pub fn parse(source: impl ::config::Source + Send + Sync + 'static) -> Self {
        // Read configuration.
        let raw_config: config::Config = config::Config::builder()
            // Start from defaults.
            .add_source(config::File::from_str(
                defaults_toml(),
                config::FileFormat::Toml,
            ))
            // Merge static configuration (from file).
            .add_source(source)
            // Merge environment overrides.
            .add_source(
                config::Environment::with_prefix("SONIC")
                    .separator("__")
                    .prefix_separator("_"),
            )
            .build()
            .expect("error reading config");

        // `#[serde(flatten)]` breaks type coercion from the `config` crate,
        // so we can’t have `crate::Config` define
        // `#[serde(flatten)] sonic: sonic::Config`. It’s a bit dirty but at
        // least we don’t have to manually add custom deserialization logic to
        // all non-string fields (in the core!).
        #[derive(serde::Deserialize)]
        pub struct ServerConfigTemp {
            pub channel: ConfigChannel,
            pub server: ConfigServer,
        }

        // Parse configuration.
        let mut server_config = raw_config
            .clone()
            .try_deserialize::<ServerConfigTemp>()
            .expect("syntax error in config");
        let mut core_config = raw_config

View on GitHub (pinned to e6a72da6a5)

Solutions

  1. Verify the config file path passed to the server exists and is readable
  2. Check env var naming: prefix SONIC_, nesting separator __ (e.g. SONIC_SERVER__LOG_LEVEL)
  3. Validate the config file syntax (JSON/YAML/TOML matches the format figment detects by extension)
  4. Run with a minimal known-good config to isolate which source fails

Example fix

// before
SONIC_SERVER_LOG_LEVEL=debug   # wrong nesting separator
// after
SONIC_SERVER__LOG_LEVEL=debug
Defensive patterns

Strategy: validation

Validate before calling

// Rust: pre-flight check before starting the server
let path = std::path::Path::new(&config_path);
if !path.exists() { panic!("config file not found: {}", config_path); }
for (k, _) in std::env::vars().filter(|(k, _)| k.starts_with("SONIC_")) {
    // env keys must use SONIC_ prefix and __ nesting separator
}

Try / catch

// Run Config::parse in a guarded startup path and print the source error
let conf = std::panic::catch_unwind(Config::parse)
    .map_err(|p| format!("config load failed: {:?}", p))?;

Prevention

When it happens

Trigger: Calling Config::parse (directly or via Task/PendingTask startup) when the config file passed (or its default location) does not exist, cannot be read, has invalid syntax at the source level, or a SONIC_* env var cannot be merged.

Common situations: Wrong --config path on startup; file permissions; env vars like SONIC_SERVER__LOG_LEVEL with values that break source building; missing config file in container images.

Related errors


AI-assisted analysis of valeriansaliou/sonic@e6a72da6a5 (2026-09-01). Data as JSON: /api/errors/39957b1568ddd4ae. Report an issue: GitHub.