can1357/oh-my-pi · error · LnError

{}: hard link not allowed for directory

Error message

{}: hard link not allowed for directory

What it means

The ln builtin's FailedToCreateHardLinkDir variant fires when a hard link to a directory is requested. Most filesystems and POSIX forbid link(2) on directories (only root may, and even then most kernels refuse with EPERM), so the tool rejects it early with the quoted directory path.

Source

Thrown at crates/pi-builtins/src/ln.rs:68

#[derive(Error, Debug)]
enum LnError {
	#[error("target {} is not a directory", _0.quote())]
	TargetIsNotADirectory(PathBuf),

	#[error("")]
	SomeLinksFailed,

	#[error("{} and {} are the same file", _0.quote(), _1.quote())]
	SameFile(PathBuf, PathBuf),

	#[error("missing destination file operand after {}", _0.quote())]
	MissingDestination(PathBuf),

	#[error("extra operand {}\nTry '{} --help' for more information.", _0.quote(), _1)]
	ExtraOperand(OsString, String),

	#[error("{}: hard link not allowed for directory", _0.to_string_lossy())]
	FailedToCreateHardLinkDir(PathBuf),

	#[error("{0}")]
	Message(String),

	#[error("{0}")]
	Io(#[from] std::io::Error),
}


mod options {
	pub const FORCE: &str = "force";
	//pub const DIRECTORY: &str = "directory";
	pub const INTERACTIVE: &str = "interactive";
	pub const NO_DEREFERENCE: &str = "no-dereference";
	pub const SYMBOLIC: &str = "symbolic";
	pub const LOGICAL: &str = "logical";
	pub const PHYSICAL: &str = "physical";

View on GitHub (pinned to 9690622007)

Solutions

  1. Use -s (symbolic link) for directories: `ln -s somedir somelink`
  2. Branch on file type: only hard-link regular files
  3. If a directory reference is needed, consider a symlink or bind mount instead

Example fix

// before
ln(&host, &["mydir", "mydir-link"])?;
// after
ln(&host, &["-s", "mydir", "mydir-link"])?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_not_dir(p: &Path) -> std::io::Result<()> {
    let md = std::fs::symlink_metadata(p)?;
    if md.is_dir() {
        return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("{}: hard link not allowed for directory", p.display())));
    }
    Ok( )
}

Type guard

fn is_regular_file(p: &Path) -> bool {
    std::fs::symlink_metadata(p).map(|m| m.is_file()).unwrap_or(false)
}

Try / catch

match ln(&host, args) {
    Err(e) if e.to_string().contains("hard link not allowed for directory") => {
        // fall back to symlink
        ln(&host, &["-s", args[0], args[1]])?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Invoking `ln somedir somelink` (hard-link mode) where somedir is a directory and -s/--symbolic was not passed.

Common situations: Users intending a symlink but forgetting -s; scripts that portably link both files and dirs without branching on type.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/0129f083be7073cc. Report an issue: GitHub.