{"record":{"id":"701eadbd9de1badc","repo":"sxyazi/yazi","slug":"urn-cannot-be-longer-than-uri","errorCode":null,"errorMessage":"URN cannot be longer than URI","messagePattern":"URN cannot be longer than URI","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"yazi-shared/src/loc/loc.rs","lineNumber":211,"sourceCode":"\t\t\t)\n\t\t}\n\t}\n\n\t#[inline]\n\tpub(crate) fn urn(self) -> P {\n\t\tunsafe {\n\t\t\tP::from_encoded_bytes_unchecked(\n\t\t\t\tself.inner.as_encoded_bytes().get_unchecked(self.inner.len() - self.urn..),\n\t\t\t)\n\t\t}\n\t}\n\n\tpub(crate) fn with<T>(path: T, uri: usize, urn: usize) -> Result<Self>\n\twhere\n\t\tT: PathView<'p, P>,\n\t{\n\t\tif urn > uri {\n\t\t\tbail!(\"URN cannot be longer than URI\");\n\t\t}\n\n\t\tlet mut loc = Self::bare(path);\n\t\tif uri == 0 {\n\t\t\t(loc.uri, loc.urn) = (0, 0);\n\t\t\treturn Ok(loc);\n\t\t} else if urn == 0 {\n\t\t\tloc.urn = 0;\n\t\t}\n\n\t\tlet mut it = loc.inner.components();\n\t\tfor i in 1..=uri {\n\t\t\tif it.next_back().is_none() {\n\t\t\t\tbail!(\"URI exceeds the entire URL\");\n\t\t\t}\n\t\t\tif i == urn {\n\t\t\t\tloc.urn = loc.strip_prefix(it.clone()).unwrap().len();\n\t\t\t}","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/sxyazi/yazi/blob/8ebf930f1796ae2076b7d6b0c5e93a1002c18134/yazi-shared/src/loc/loc.rs#L193-L229","documentation":"`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\".","triggerScenarios":"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)`.","commonSituations":"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.","solutions":["Swap or fix the arguments so `urn <= uri` at the call site.","Recompute the component counts from the same path value passed to `with`.","If only the file-name tail is needed, pass `urn == uri` (e.g. `with(path, n, n)`), never a larger urn.","Add a debug_assert or pre-check on the counts before the call during development."],"exampleFix":"// before\nlet loc = Loc::with(url, uri_components, urn_components); // urn_components > uri_components\n// after\nlet urn_components = urn_components.min(uri_components);\nlet loc = Loc::with(url, uri_components, urn_components)?;","handlingStrategy":"validation","validationCode":"fn safe_with(path: &Url, uri: usize, urn: usize) -> anyhow::Result<Loc> {\n    anyhow::ensure!(urn <= uri, \"urn ({urn}) must be <= uri ({uri})\");\n    Loc::with(path, uri, urn)\n}","typeGuard":null,"tryCatchPattern":"let loc = Loc::with(url, uri, urn.min(uri))\n    .wrap_err(\"building Loc for hover\")?;","preventionTips":["Always clamp urn to uri at the call site.","Derive both counts from the same path value in the same expression.","Check argument order (path, uri, urn) — swapping them triggers this.","Add a debug_assert!(urn <= uri) near hot hover/parent paths."],"tags":["rust","url","invariant","yazi-shared"],"backgroundTag":"invalid-path-component-count","analyzedSha":"8ebf930f1796ae2076b7d6b0c5e93a1002c18134","analyzedAt":"2026-09-02T18:38:25.566Z","contentChangedAt":"2026-09-02T18:38:25.566Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}