can1357/oh-my-pi · error · TouchError

failed to get attributes of {}: {}

Error message

failed to get attributes of {}: {}

What it means

TouchError::ReferenceFileInaccessible is raised when `touch -r <reference>` cannot stat the reference file whose timestamps should be copied. The library needs the reference's atime/mtime via metadata() and wraps the io::Error with the quoted path. It mirrors GNU coreutils' 'failed to get attributes of' diagnostics.

Source

Thrown at crates/pi-builtins/src/touch.rs:45

use rustix::fs::Timestamps;
#[cfg(unix)]
use rustix::fs::futimens;
#[cfg(target_os = "linux")]
use uucore::libc;
use uucore::{display::Quotable, parser::shortcut_value_parser::ShortcutValueParser};

use brush_core::{ShellExtensions, builtins::Registration};
use thiserror::Error as ThisError;

use crate::host::{Host, Utility, format_usage, matches_parser, util};

#[derive(Debug, ThisError)]
enum TouchError {
	#[error("Unable to parse date: {0}")]
	InvalidDateFormat(String),
	#[error("Source has invalid access or modification time: {0}")]
	InvalidFiletime(FileTime),
	#[error("failed to get attributes of {}: {}", .0.quote(), io_error(.1))]
	ReferenceFileInaccessible(PathBuf, std::io::Error),
	#[cfg(windows)]
	#[error("GetFinalPathNameByHandleW failed with code {0}")]
	WindowsStdoutPathError(String),
	#[error("{0}")]
	Message(String),
}

fn io_error(error: &std::io::Error) -> String {
	if error.raw_os_error().is_some() {
		match error.kind() {
			ErrorKind::NotFound => "No such file or directory".into(),
			ErrorKind::PermissionDenied => "Permission denied".into(),
			ErrorKind::AlreadyExists => "Already exists".into(),
			ErrorKind::WouldBlock => "Would block".into(),
			_ => error.to_string().split(" (os error ").next().unwrap_or_default().into(),
		}
	} else {

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the reference file exists and its parent directory grants you search (execute) permission
  2. Re-run with the correct path or create the reference file first
  3. If you only need fixed timestamps, use -d/-t with an explicit date instead of -r
  4. Check quoting of the path (spaces/special characters) in your shell invocation

Example fix

// before: touch -r missing_ref.txt target.txt  -> fails
// after
let ref_path = "missing_ref.txt";
if !std::path::Path::new(ref_path).exists() {
    // fall back to an explicit date
    // touch -d "2026-01-01 00:00" target.txt
}
Defensive patterns

Strategy: validation

Validate before calling

fn validate_reference(path: &std::path::Path) -> Result<(), String> {
    match std::fs::metadata(path) {
        Ok(_) => Ok(()),
        Err(e) => Err(format!("reference '{}' inaccessible: {}", path.display(), e)),
    }
}

Try / catch

match result {
    Err(TouchError::ReferenceFileInaccessible(path, io)) => {
        eprintln!("reference {} failed: {} — falling back to explicit date", path.display(), io);
        // proceed with -d explicit timestamp
    }
    other => other.map(|_| ()),
}

Prevention

When it happens

Trigger: Calling touch with `-r/--reference=FILE` where FILE does not exist, lacks read permission on its directory, or the path is otherwise unstat-able (broken symlink target, permission denied).

Common situations: Copy-pasting a reference path with a typo; referencing a file in another user's directory; the reference file was deleted between listing and touching; running without sufficient privileges (e.g. in restricted CI containers).

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 can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/aa1f5c6939815a09. Report an issue: GitHub.