tinyhumansai/openhuman · error
Failed to read config file: {}{ownership}
Error message
Failed to read config file: {}{ownership} What it means
config_path could not be read for a reason that is deliberately NOT auto-recovered: unlike content corruption (InvalidData, which triggers rename-to-.corrupted plus .bak fallback plus defaults), transient/permission errors such as PermissionDenied or NotFound are propagated to the caller so the user sees them. The {ownership} suffix annotates file-ownership context. Returning an empty string here would silently mask a permissions problem as 'no config', so the read error is surfaced.
Source
Thrown at src/openhuman/config/schema/load/impl_load.rs:42
/// Try to read `config_path`. On content corruption (non-UTF-8 bytes), rename
/// the corrupted file to `<config_file>.corrupted.<timestamp>`, try the `.bak`
/// backup, and if that also fails return an empty string so the caller's
/// `parse_config_with_recovery` falls through to defaults.
///
/// Only triggers auto-recovery for **content** corruption (`InvalidData`), not
/// for transient or permission errors (`PermissionDenied`, `NotFound`, etc.),
/// which are propagated as errors so the caller can surface them to the user.
///
/// Rate-limits the warning to at most one per process lifetime so a
/// permanently corrupted file does not flood telemetry (#5167).
async fn read_config_with_recovery_or_default(config_path: &Path) -> Result<(String, bool)> {
let reads = || async {
match fs::read_to_string(config_path).await {
Ok(contents) => Ok(contents),
Err(error) => {
let ownership = describe_config_ownership(config_path).await;
Err(anyhow::Error::new(error).context(format!(
"Failed to read config file: {}{ownership}",
config_path.display()
)))
}
}
};
let result =
crate::openhuman::util::retry_with_backoff_async("read config file", 5, 20, reads).await;
match result {
Ok(contents) => Ok((contents, false)),
Err(e) => {
// Check if this is a content-corruption error (non-UTF-8).
// Only in that case do we auto-recover by renaming the file
// and falling back to backup/defaults. Other errors (permission
// denied, file not found after retries, etc.) are propagated
// so the caller surfaces them to the user.
let is_content_corruption = e.chain().any(|cause| {View on GitHub (pinned to 7491200858)
Solutions
- Check the file permissions/ownership of the config file and correct them (chmod/chown) so the process can read it
- Verify config_path actually exists and the parent directories are accessible
- If the error is transient (e.g. disk/IO), retry starting the core once the underlying issue clears
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at src/openhuman/config/schema/load/impl_load.rs:42 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/16ce4363f8e1c94f.
Report an issue: GitHub.