linera-io/linera-protocol · error · std::io::Error
file is empty or does not exist: {}
Error message
file is empty or does not exist: {} What it means
`linera_persistent::file::File::read` loads a JSON-persisted value (wallets, configs) from a path and is the strict variant of `read_or_create`: if the file is missing or zero bytes, the value-creation closure itself returns `std::io::ErrorKind::NotFound` with this message. The file is flock-locked and atomically rewritten through a `<path>.json.new` staging file, so an empty main file usually means it was never written or was truncated externally.
Source
Thrown at linera-persistent/src/file.rs:155
.write(true)
.create(true)
.open(path)?,
)
.map_err(|source| Error::Lock {
path: path.into(),
source,
})?,
path: path.into(),
value,
};
this.save()?;
Ok(this)
}
/// Reads the value from a file at `path`, returning an error if it does not exist.
pub fn read(path: &Path) -> Result<Self, Error> {
Self::read_or_create(path, || {
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("file is empty or does not exist: {}", path.display()),
)
.into())
})
}
/// Reads the value from a file at `path`, calling the `value` function to create it
/// if it does not exist. If it does exist, `value` will not be called.
pub fn read_or_create(
path: &Path,
value: impl FnOnce() -> Result<T, Error>,
) -> Result<Self, Error> {
let lock = Lock::new(open_options().read(true).open(path)?)?;
let mut reader = io::BufReader::new(&lock.0);
let file_is_empty = reader.fill_buf()?.is_empty();
let me = Self {View on GitHub (pinned to 6c226ddcb3)
Solutions
- Verify the path exists and is non-empty before reading.
- Create the file first with the tool's creation command, or use `File::read_or_create(path, || Ok(default_value))` instead of `File::read`.
- If the file was expected to exist, restore it from backup — an empty file means there is no state to recover via `read`.
- Check for a leftover `<path>.json.new` staging file if a crash interrupted a save.
Example fix
// before let wallet = File::<Wallet>::read(&path)?; // NotFound if path missing/empty // after let wallet = File::<Wallet>::read_or_create(&path, || Ok(Wallet::default()))?;
Defensive patterns
Strategy: validation
Validate before calling
use std::path::Path;
fn readable(p: &Path) -> bool {
std::fs::metadata(p).map(|m| m.len() > 0).unwrap_or(false)
} Try / catch
match File::<T>::read(&path) { Ok(f) => f, Err(e) if e.to_string().contains("file is empty or does not exist") => File::read_or_create(&path, T::default)?, Err(e) => return Err(e.into()) } Prevention
- Run the wallet-creation step before any command that reads an existing wallet.
- Default to read_or_create with an explicit default value for first-run paths.
- Check for leftover .json.new staging files after crashes.
- Guard scripts against empty-string path variables.
When it happens
Trigger: Passing a wallet/config path that does not exist (typo, wrong `--wallet` argument); pointing at a fresh directory without running the creation step; a zero-byte file left by manual truncation or an interrupted external process.
Common situations: First run of a tool that expects an existing wallet instead of creating one; scripts referencing `$HOME` under a different user; renamed or moved data directories; CI starting with a clean environment.
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
- wallet not found at {}
- Failed to deserialize instantiation argument {argument:?}
- Query {argument:?} is invalid and could not be deserialized
- Chain {chain_id} not found.
- Failed to save claims to database: {e}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/918b93438bc16278.
Report an issue: GitHub.