Name the failed operation
“Invalid input” says almost nothing. “Cannot read notes/index.md” identifies
both the attempted operation and its target. The underlying operating-system
error can then explain why it failed.
Context should earn its place
Repeatedly wrapping the same error makes a message longer without making it more useful. Add context at the boundary that knows the concrete operation; let clear errors pass through intermediate layers unchanged.
let source = fs::read_to_string(path) .with_context(|| format!("cannot read {}", path.display()))?;
Thanks for reading. If this sparked an idea, keep it moving. Browse the archive.