sxyazi/yazi · error · anyhow::Error

Target URL must be absolute

Error message

Target URL must be absolute

What it means

Raised by TryFrom<u16> for ChaMode (yazi-fs/src/cha/mode.rs:66) when bitflags' from_bits rejects a raw mode value because it contains bits outside the declared ChaMode flag set. The declared flags cover type bits (0xF000), special bits (SUID/SGID/sticky), and rwx permission bits, which together occupy all 16 bits, so in practice from_bits only fails for values with extension/reserved bits a future format might introduce; a wrong file-type nibble instead produces the sibling `invalid file type` error on line 75.

Source

Thrown at yazi-actor/src/mgr/displace_do.rs:28

pub struct DisplaceDo;

impl Actor for DisplaceDo {
	type Form = DisplaceDoForm;

	const NAME: &str = "displace_do";

	fn act(cx: &mut Ctx, Self::Form { opt }: Self::Form) -> Result<Data> {
		if cx.cwd() != opt.from {
			succ!()
		}

		let to = match opt.to {
			Ok(url) => url,
			Err(e) => return act!(mgr:update_files, cx, FilesOp::IOErr(opt.from, e)),
		};

		if !to.is_absolute() {
			bail!("Target URL must be absolute");
		} else if let Some(hovered) = cx.hovered()
			&& let Ok(url) = to.try_join(hovered.urn())
		{
			act!(mgr:reveal, cx, (url, CdSource::Displace))
		} else {
			act!(mgr:cd, cx, (to, CdSource::Displace))
		}
	}
}

View on GitHub (pinned to 441b332de8)

Solutions

  1. Mask the incoming value to the known bit set before converting (value & 0xFFFF with only defined flags, e.g. strip extension bits)
  2. Fix the producer to emit a mode within the documented layout (type nibble must be one of T_FILE/T_DIR/T_LINK/T_BLOCK/T_CHAR/T_SOCK/T_FIFO)
  3. If the type nibble is the problem (error text says `invalid file type`), map unknown types to ChaType::Unknown via from_bare instead of try_from
  4. Align versions on both ends when Cha data crosses processes

Example fix

// before
let mode = ChaMode::try_from(raw_mode)?;
// after
let mode = ChaMode::try_from(raw_mode & 0o7777 | type_bits)?; // strip undefined bits
// or for unknown types:
let mode = ChaMode::from_bare(ChaType::Unknown);
Defensive patterns

Strategy: validation

Validate before calling

// Rust: check the type nibble and mask unknown bits before converting
const T_MASK: u16 = 0xF000;
let masked = value & 0xFFFF;
let type_ok = matches!(masked & T_MASK,
    0x8000 | 0x4000 | 0xA000 | 0x6000 | 0x2000 | 0xC000 | 0x1000);
let mode = if type_ok { ChaMode::try_from(masked)? } else { ChaMode::from_bare(ChaType::Unknown) };

Type guard

// Rust
fn is_known_mode(v: u16) -> bool {
    ChaMode::from_bits(v).is_some_and(|m| matches!(m & ChaMode::T_MASK,
        ChaMode::T_FILE | ChaMode::T_DIR | ChaMode::T_LINK | ChaMode::T_BLOCK
        | ChaMode::T_CHAR | ChaMode::T_SOCK | ChaMode::T_FIFO))
}

Try / catch

// Rust: degrade to Unknown instead of failing
let mode = ChaMode::try_from(raw).unwrap_or_else(|_| ChaMode::from_bare(ChaType::Unknown));

Prevention

When it happens

Trigger: Calling ChaMode::try_from(value) with a hand-composed u16 that sets undefined bits (e.g. bits reserved by a new stat format or a corrupted mode read over DDS); deserializing a mode from an external/remote source whose encoding includes extra flag bits; note the distinct `invalid file type` error occurs when the type nibble is 0/unknown or a non-mapped combination.

Common situations: Interop code marshalling st_mode between platforms or over the network with a different bit layout; custom filesystems/FUSE reporting unusual mode bits; version skew between a yazi instance serializing Cha and an older one parsing it.

Related errors


AI-assisted analysis of sxyazi/yazi@441b332de8 (2026-08-19). Data as JSON: /api/errors/254af54cc0a8a8a8. Report an issue: GitHub.