can1357/oh-my-pi · error · LnError

2

2

Error message

target {} is not a directory

What it means

LnError::TargetIsNotADirectory is thrown by the ln builtin when link creation is requested inside a target path that exists but is not a directory — i.e., the caller asked for links to be placed in a directory (form `ln source... target-dir/`) but the target is a regular file or other non-directory. It carries the offending PathBuf, shell-quoted in the message, and surfaces with OS error code 2 (InvalidInput-class io error).

Source

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

	symbolic:       bool,
	relative:       bool,
	logical:        bool,
	target_dir:     Option<PathBuf>,
	no_target_dir:  bool,
	no_dereference: bool,
	verbose:        bool,
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum OverwriteMode {
	NoClobber,
	Interactive,
	Force,
}

#[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}")]

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the target path is a directory (ls -ld target) or create it with mkdir -p before linking
  2. Remove or rename the non-directory file occupying the target path
  3. Pass a single source when creating a named link instead of the directory-target form
  4. If the path is a symlink, ensure it resolves to a directory

Example fix

// before
ln(["a.txt", "b.txt", "dest"], {}); // dest is a regular file
// after
fs::create_dir_all("dest");
ln(["a.txt", "b.txt", "dest"], {});
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_dir_target(target: &std::path::Path) -> std::io::Result<()> {
	let md = std::fs::metadata(target)?;
	if !md.is_dir() {
		return Err(std::io::Error::new(
			std::io::ErrorKind::InvalidInput,
			format!("{} is not a directory", target.display()),
		));
	}
	Ok(())
}

Try / catch

match ln_result {
	Err(e) if e.to_string().contains("is not a directory") => {
		eprintln!("create or fix the target directory first: {e}");
	}
	Err(e) => return Err(e),
	Ok(()) => /* ... */,
}

Prevention

When it happens

Trigger: Calling the ln builtin with multiple sources and a final target argument that resolves to an existing non-directory file (e.g. `ln a b c existing-file` expecting 'existing-file' to be a directory); creating a hard/symbolic link where the destination directory component is actually a file.

Common situations: Typos where the intended directory name collides with an existing file name; scripts assuming a directory exists but a file was created there earlier; passing a symlink to a file as the target directory.

Related errors


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