{"id":"7c1610d892b5497e","repo":"rust-lang/rust","slug":"path-component-of-path-is-an-invalid-filen","errorCode":null,"errorMessage":"Path component {:?} of path {} is an invalid filename","messagePattern":"Path component (.+?) of path (.+?) is an invalid filename","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs","lineNumber":24,"sourceCode":"use cranelift_codegen::MachSrcLoc;\nuse cranelift_codegen::binemit::CodeOffset;\nuse gimli::write::{FileId, FileInfo, LineProgram, LineString, LineStringTable};\nuse rustc_span::{\n    FileName, Pos, RemapPathScopeComponents, SourceFile, SourceFileAndLine,\n    SourceFileHashAlgorithm, hygiene,\n};\n\nuse crate::debuginfo::FunctionDebugContext;\nuse crate::debuginfo::emit::address_for_func;\nuse crate::prelude::*;\n\n// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.\nfn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {\n    let mut iter = path.components();\n    let file_name = match iter.next_back() {\n        Some(Component::Normal(p)) => p,\n        component => {\n            panic!(\n                \"Path component {:?} of path {} is an invalid filename\",\n                component,\n                path.display()\n            );\n        }\n    };\n    let parent = iter.as_path();\n    (parent, file_name)\n}\n\n// OPTIMIZATION: Avoid UTF-8 validation on UNIX.\nfn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {\n    #[cfg(unix)]\n    {\n        use std::os::unix::ffi::OsStrExt;\n        path.as_bytes()\n    }\n    #[cfg(not(unix))]","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs#L6-L42","documentation":"Panics inside split_path_dir_and_file while generating .debug_line info when the last component of a source path is not a Component::Normal (i.e. it is RootDir, CurDir, ParentDir, or a Windows Prefix). gimli's LineProgram requires an ordinary file-name OsStr, so an unusual path aborts debuginfo emission.","triggerScenarios":"Reached during debuginfo line-program construction (line_info.rs ~107 calls split_path_dir_and_file on each source file path). The panic fires for any source file whose path, after remapping, ends in something that is not a normal filename component.","commonSituations":"A --remap-path-prefix mapping collapses a path to `/` or `.` so the final component becomes RootDir/CurDir; proc-macro or macro-expanded spans synthesize a virtual filename like `<anon>` or `<macro>` mapped to a bare root; a Windows UNC or disk prefix leaks through as the last component on non-Windows; source paths produced by out-of-tree builds with trailing separators.","solutions":["Inspect the failing path printed in the panic (the `{}` is path.display()) and identify which crate/file produces it.","Audit --remap-path-prefix / RUSTFLAGS remapping rules to ensure no rule maps a source root to `/`, `.`, or an empty string.","Reproduce with `--remap-path-prefix=<bad>=<good>` inverted to find the offending rule, then fix the rule.","If the path comes from a generated/build-script file, ensure the generator emits a real filename rather than a bare root or sentinel."],"exampleFix":"// before\nlet file_name = match iter.next_back() {\n    Some(Component::Normal(p)) => p,\n    component => {\n        panic!(\"Path component {:?} of path {} is an invalid filename\", component, path.display());\n    }\n};\n// after\nlet file_name = match iter.next_back() {\n    Some(Component::Normal(p)) => p,\n    Some(other) => {\n        // Fall back to the OsStr of whatever component we got so debuginfo can still emit.\n        eprintln!(\"cg_clif: path component {:?} of {} is not Normal; using as-is\", other, path.display());\n        other.as_os_str()\n    }\n    None => panic!(\"Path {} has no components\", path.display()),\n};","handlingStrategy":"validation","validationCode":"use std::path::{Path, Component};\nfn validate_path(p: &Path) -> Result<(), String> {\n    for c in p.components() {\n        if let Component::Normal(os_str) = c {\n            if os_str.to_str().is_none() {\n                return Err(format!(\"path component {:?} in {} is not valid Unicode / contains illegal chars\", os_str, p.display()));\n            }\n            let s = os_str.to_str().unwrap();\n            if s.is_empty() || s.contains('\\0') {\n                return Err(format!(\"path component {:?} is empty or contains NUL\", s));\n            }\n            #[cfg(windows)]\n            for bad in ['<', '>', ':', '\"', '/', '\\\\', '|', '?', '*'] {\n                if s.contains(bad) { return Err(format!(\"component {:?} has illegal char {:?}\", s, bad)); }\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":"use std::path::Path;\nfn path_components_are_valid_filenames(p: &Path) -> bool {\n    p.components().all(|c| match c {\n        std::path::Component::Normal(os) => os.to_str().map(|s| !s.is_empty() && !s.contains('\\0')).unwrap_or(false),\n        _ => true,\n    })\n}","tryCatchPattern":null,"preventionTips":["Keep all source / output paths pure UTF-8 with no NUL bytes; cg_clif emits DWARF using these names.","Avoid path components with OS-illegal characters (<>:\\\"/\\\\|?* on Windows).","Do not build inside directories whose names were created from raw bytes or non-Unicode locales.","Use stable, ASCII-friendly crate names and target paths to keep debuginfo filename emission safe."],"tags":["cg-clif","debuginfo","gimli","path-handling","panic"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}