{"record":{"id":"d233d4e76749666c","repo":"getzola/zola","slug":"couldn-t-get-filename-from-page-asset","errorCode":null,"errorMessage":"Couldn't get filename from page asset","messagePattern":"Couldn't get filename from page asset","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"components/site/src/lib.rs","lineNumber":709,"sourceCode":"        let mut imageproc =\n            self.imageproc.lock().expect(\"Couldn't lock imageproc (process_images)\");\n        imageproc.prune()?;\n        imageproc.do_process()\n    }\n\n    /// Deletes the `public` directory if it exists and the `preserve_dotfiles_in_output` option is set to false,\n    /// or if set to true: its contents except for the dotfiles at the root level.\n    pub fn clean(&self) -> Result<()> {\n        clean_site_output_folder(&self.output_path, self.config.preserve_dotfiles_in_output)\n    }\n\n    fn copy_assets(&self, parent: &Path, assets: &[impl AsRef<Path>], dest: &Path) -> Result<()> {\n        for asset in assets {\n            let asset_path = asset.as_ref();\n            copy_file_if_needed(\n                asset_path,\n                &dest.join(\n                    asset_path.strip_prefix(parent).expect(\"Couldn't get filename from page asset\"),\n                ),\n                self.config.hard_link_static,\n            )?;\n        }\n\n        Ok(())\n    }\n\n    /// Deletes the `public` directory (only for `zola build`) and builds the site\n    pub fn build(&self) -> Result<()> {\n        let mut start = Instant::now();\n        // Do not clean on `zola serve` otherwise we end up copying assets all the time\n        if self.build_mode == BuildMode::Disk {\n            self.clean()?;\n        }\n        start = log_time(start, \"Cleaned folder\");\n\n        // Generate/move all assets before markdown any content","sourceCodeStart":691,"sourceCodeEnd":727,"githubUrl":"https://github.com/getzola/zola/blob/61d30828217957120309db657950224edf9707e2/components/site/src/lib.rs#L691-L727","documentation":"Site::copy_assets copies page asset files, computing each asset's destination relative to the parent path via Path::strip_prefix. It panics with this expect when an asset path does not start with the given parent prefix, meaning the asset lies outside the page's content directory.","triggerScenarios":"Calling site building/copy logic where a page's assets slice contains a path that is not a descendant of parent — e.g. a manually registered asset path outside the .md file's directory, or a normalized/aliased path that diverges from parent.","commonSituations":"Symlinked content directories where canonicalization changes the prefix; custom page/asset wiring that passes absolute or ../ paths; cross-platform path separator mismatches when parent was built differently from asset_path.","solutions":["Ensure every asset passed with a page lives under that page's directory (same content dir).","Canonicalize both parent and asset paths (fs::canonicalize / std::path::absolute) before the strip so symlinks don't break the prefix.","Check for path separator or case mismatches (Windows vs Unix) between parent and asset.","Copy out-of-page assets via a static/ path instead of page-attached assets."],"exampleFix":"// before\nasset_path.strip_prefix(parent).expect(\"Couldn't get filename from page asset\")\n// after\nlet canon_parent = parent.canonicalize()?;\nlet canon_asset = asset_path.canonicalize()?;\ncanon_asset.strip_prefix(&canon_parent).expect(\"asset outside page dir\")","handlingStrategy":"validation","validationCode":"// Validate every asset is under the page dir before building\nfor asset in assets {\n    let p = std::fs::canonicalize(asset.as_ref())?;\n    assert!(p.starts_with(std::fs::canonicalize(parent)?), \"asset {:?} outside page dir {:?}\", p, parent);\n}","typeGuard":"fn asset_under_parent(asset: &Path, parent: &Path) -> bool {\n    let (a, p) = (asset.canonicalize().ok(), parent.canonicalize().ok());\n    match (a, p) { (Some(a), Some(p)) => a.starts_with(p), _ => false }\n}","tryCatchPattern":"std::panic::catch_unwind(|| copy_assets(...)).map_err(|_| anyhow!(\"asset path outside page directory\"))?","preventionTips":["Keep page-attached assets inside the page's content directory.","Canonicalize paths (resolve symlinks) before path-prefix comparisons.","Don't mix absolute and relative asset paths when wiring pages.","Use static/ for assets shared across or outside pages."],"tags":["path","filesystem","strip-prefix","panic"],"backgroundTag":"path-prefix-mismatch","analyzedSha":"61d30828217957120309db657950224edf9707e2","analyzedAt":"2026-09-03T14:39:09.727Z","contentChangedAt":"2026-09-03T14:39:09.727Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}