databendlabs/databend · error

raft_dir of meta service must be an absolute path, but got

Error message

raft_dir of meta service must be an absolute path, but got: {:?}

What it means

`load_meta_config` validates that the meta service's `raft_config.raft_dir` is an absolute path (starts with `/`) and returns this error when it is not. The restore path needs to locate the raft data directory directly, so a relative path would resolve against an unpredictable working directory.

Solutions

  1. Edit the meta config file and set `raft_config.raft_dir` to an absolute path (e.g. `/var/lib/databend/meta`).
  2. Verify the directory actually exists and contains the raft data before restoring.
  3. If the config is generated by a script, make the script emit absolute paths.
  4. Re-run restore after fixing the path.

Example fix

// before (meta config toml)
[raft_config]
raft_dir = "./meta_data"

// after
[raft_config]
raft_dir = "/var/lib/databend/meta_data"
Defensive patterns

Strategy: validation

Validate before calling

let dir = cfg["raft_config"]["raft_dir"].as_str().unwrap();
if !dir.starts_with('/') {
    return Err(format!("raft_dir must be absolute, got: {dir}"));
}
if !std::path::Path::new(dir).is_dir() {
    return Err(format!("raft_dir does not exist: {dir}"));
}

Type guard

fn is_absolute_existing_dir(p: &str) -> bool {
    p.starts_with('/') && std::path::Path::new(p).is_dir()
}

Try / catch

match bendsave::load_meta_config(path) {
    Ok(cfg) => cfg,
    Err(e) if e.to_string().contains("raft_dir") => {
        eprintln!("fix raft_dir in {path}: {e}");
        std::process::exit(2);
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling `load_meta_config` (directly or via `restore`) with a meta config whose `[raft_config] raft_dir` value is relative, e.g. `"./meta"` or `"meta_data"`.

Common situations: Hand-written or copied meta configs using relative paths; configs generated for environments where the meta process was launched from a fixed working directory so a relative path happened to work there.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/9a511a571964b93f. Report an issue: GitHub.

Appendix: source

Thrown at src/bendsave/src/storage.rs:85

pub fn load_query_storage(cfg: &InnerConfig) -> Result<Operator> {
    let op = init_operator(&cfg.storage.params)?;
    debug!("databend storage loaded: {:?}", op.info());
    Ok(op)
}

/// Load the configuration file of databend meta.
///
/// The given input is the path to databend meta's configuration file.
pub fn load_meta_config(path: &str) -> Result<MetaServiceConfig> {
    let content = std::fs::read_to_string(path)?;
    let outer_config: databend_meta_cli_config::Config = toml::from_str(&content)?;
    let meta_config: MetaConfig = outer_config
        .try_into()
        .map_err(|msg: String| anyhow!("{msg}"))?;
    let service_config = meta_config.service;

    if !service_config.raft_config.raft_dir.starts_with("/") {
        return Err(anyhow!(
            "raft_dir of meta service must be an absolute path, but got: {:?}",
            service_config.raft_config.raft_dir
        ));
    }

    debug!("databend meta storage loaded: {:?}", service_config);
    Ok(service_config)
}

/// Init databend query instance so that we can read meta and check license
/// for it.
///
/// FIXME: I really don't like this pattern, but it's how databend work.
pub fn init_query(cfg: &InnerConfig) -> Result<()> {
    GlobalInstance::init_production();

    GlobalConfig::init(cfg, &BUILD_INFO)?;
    GlobalIORuntime::init(cfg.storage.num_cpus as usize)?;

View on GitHub (pinned to 288d84d76e)