linera-io/linera-protocol · error

Unable to read validator options file

Error message

Unable to read validator options file

What it means

Panic raised by `linera-service server generate` when `fs_err::tokio::read_to_string` fails on one of the files passed via `--validators <path>`. The file must exist, be readable by the current user, and contain valid UTF-8, because it is immediately parsed as TOML into ValidatorOptions. Since `.expect()` is used, the whole CLI command aborts with this message plus the underlying std::io::Error (fs_err decorates it with the failing path).

Source

Thrown at linera-service/src/server.rs:896

            store_config
                .run_with_storage(wasm_runtime, allow_application_logs, cache_sizes, job)
                .boxed()
                .await
                .unwrap()
                .unwrap();
        }

        ServerCommand::Generate {
            validators,
            committee,
            testing_prng_seed,
        } => {
            let mut config_validators = Vec::new();
            let mut rng = Box::<dyn CryptoRng>::from(testing_prng_seed);
            for options_path in validators {
                let options_string = fs_err::tokio::read_to_string(options_path)
                    .await
                    .expect("Unable to read validator options file");
                let options: ValidatorOptions = toml::from_str(&options_string)
                    .unwrap_or_else(|_| panic!("Invalid options file format: \n {options_string}"));
                let path = options.server_config_path.clone();
                let mut server = make_server_config(&path, &mut rng, options)
                    .expect("Unable to open server config file");
                Persist::persist(&mut server)
                    .await
                    .expect("Unable to write server config file");
                info!("Wrote server config {}", path.to_str().unwrap());
                println!(
                    "{},{}",
                    server.validator.public_key, server.validator.account_key
                );
                config_validators.push(Persist::into_value(server).validator);
            }
            if let Some(committee) = committee {
                let mut config = persistent::File::new(
                    &committee,

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Verify the file exists and is readable (`ls -l <path>`, `cat <path>`) and contains readable TOML text.
  2. Pass an absolute path, or re-run the command from the directory the relative path is based on.
  3. Fix permissions or ownership: `chmod +r <file>` / `chown $(id -un) <file>`, and confirm the container user can read it.
  4. If embedding this code path, replace `.expect(...)` with `.with_context(...)?` so the decorated io::Error is reported instead of a panic.

Example fix

// before
let options_string = fs_err::tokio::read_to_string(options_path)
    .await
    .expect("Unable to read validator options file");
// after
let options_string = fs_err::tokio::read_to_string(&options_path)
    .await
    .with_context(|| format!("unable to read validator options file: {}", options_path.display()))?;
Defensive patterns

Strategy: validation

Validate before calling

let meta = fs_err::metadata(&options_path)
    .with_context(|| format!("validator options file not found: {}", options_path.display()))?;
anyhow::ensure!(meta.is_file(), "not a regular file: {}", options_path.display());
let bytes = fs_err::read(&options_path)?;
anyhow::ensure!(std::str::from_utf8(&bytes).is_ok(), "validator options file is not valid UTF-8");

Try / catch

let options_string = match fs_err::tokio::read_to_string(&options_path).await {
    Ok(s) => s,
    Err(err) => {
        eprintln!("error: unable to read validator options file: {err}");
        std::process::exit(1);
    }
};

Prevention

When it happens

Trigger: Running `linera-service server generate --validators <path> ...` where the path does not exist, is a directory, has no read permission, or contains non-UTF-8 bytes; also when a relative path is resolved against a different working directory than the one assumed.

Common situations: Typo'd or relative --validators path used from the wrong cwd; options file copied from another machine/user without read permission; container running as non-root against a root-owned file; provisioning scripts referencing a temp options file that was already cleaned up.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/f483e23455039317. Report an issue: GitHub.