sxyazi/yazi · critical

URN cannot be longer than URI

Error message

URN cannot be longer than URI

What it means

`Loc::with` builds a `Loc` — a URL with cached byte offsets marking the URI (ancestors tail) and URN (file-name tail) boundaries within the path. The invariant `urn <= uri` must hold: the URN region is always a suffix-subset of the URI region. Passing `urn > uri` violates that invariant and bails with "URN cannot be longer than URI".

Source

Thrown at yazi-shared/src/loc/loc.rs:211

			)
		}
	}

	#[inline]
	pub(crate) fn urn(self) -> P {
		unsafe {
			P::from_encoded_bytes_unchecked(
				self.inner.as_encoded_bytes().get_unchecked(self.inner.len() - self.urn..),
			)
		}
	}

	pub(crate) fn with<T>(path: T, uri: usize, urn: usize) -> Result<Self>
	where
		T: PathView<'p, P>,
	{
		if urn > uri {
			bail!("URN cannot be longer than URI");
		}

		let mut loc = Self::bare(path);
		if uri == 0 {
			(loc.uri, loc.urn) = (0, 0);
			return Ok(loc);
		} else if urn == 0 {
			loc.urn = 0;
		}

		let mut it = loc.inner.components();
		for i in 1..=uri {
			if it.next_back().is_none() {
				bail!("URI exceeds the entire URL");
			}
			if i == urn {
				loc.urn = loc.strip_prefix(it.clone()).unwrap().len();
			}

View on GitHub (pinned to 8ebf930f17)

Solutions

  1. Swap or fix the arguments so `urn <= uri` at the call site.
  2. Recompute the component counts from the same path value passed to `with`.
  3. If only the file-name tail is needed, pass `urn == uri` (e.g. `with(path, n, n)`), never a larger urn.
  4. Add a debug_assert or pre-check on the counts before the call during development.

Example fix

// before
let loc = Loc::with(url, uri_components, urn_components); // urn_components > uri_components
// after
let urn_components = urn_components.min(uri_components);
let loc = Loc::with(url, uri_components, urn_components)?;
Defensive patterns

Strategy: validation

Validate before calling

fn safe_with(path: &Url, uri: usize, urn: usize) -> anyhow::Result<Loc> {
    anyhow::ensure!(urn <= uri, "urn ({urn}) must be <= uri ({uri})");
    Loc::with(path, uri, urn)
}

Try / catch

let loc = Loc::with(url, uri, urn.min(uri))
    .wrap_err("building Loc for hover")?;

Prevention

When it happens

Trigger: Calling `Loc::with(path, uri, urn)` (crate-internal, via constructors like hover/parent derivations) with a urn component count strictly greater than the uri component count, e.g. `with(path, 1, 2)`.

Common situations: Bugs in code computing how many components to strip for urn vs uri (off-by-one or swapped arguments); passing a count derived from one path to a `with` call on a different, shorter path; internal refactors of hover/spot logic that misorder the two counters.

Related errors


AI-assisted analysis of sxyazi/yazi@8ebf930f17 (2026-09-02). Data as JSON: /api/errors/701eadbd9de1badc. Report an issue: GitHub.