{"record":{"id":"02b142eef365a479","repo":"astral-sh/ruff","slug":"path-is-not-valid-utf-8","errorCode":null,"errorMessage":"path `{}` is not valid UTF-8","messagePattern":"path `(.+?)` is not valid UTF-8","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ty_completion_eval/src/main.rs","lineNumber":561,"sourceCode":"fn copy_project(src_dir: &SystemPath, dst_dir: &SystemPath) -> anyhow::Result<Vec<Cursor>> {\n    std::fs::create_dir_all(dst_dir).with_context(|| dst_dir.to_string())?;\n\n    let mut cursors = vec![];\n    let it = walkdir::WalkDir::new(src_dir.as_std_path())\n        .sort_by_file_name()\n        .into_iter()\n        .filter_entry(|dent| {\n            !dent\n                .file_name()\n                .to_str()\n                .is_some_and(|name| name.starts_with('.'))\n        });\n    for result in it {\n        let dent =\n            result.with_context(|| format!(\"failed to get directory entry from {src_dir}\"))?;\n\n        let src = SystemPath::from_std_path(dent.path()).ok_or_else(|| {\n            anyhow::anyhow!(\"path `{}` is not valid UTF-8\", dent.path().display())\n        })?;\n        let name = src\n            .strip_prefix(src_dir)\n            .expect(\"descendent of `src_dir` must start with `src`\");\n        // let name = src\n        // .file_name()\n        // .ok_or_else(|| anyhow::anyhow!(\"path `{src}` is missing a basename\"))?;\n        let dst = dst_dir.join(name);\n        if dent.file_type().is_dir() {\n            std::fs::create_dir_all(dst.as_std_path())\n                .with_context(|| format!(\"failed to create directory `{dst}`\"))?;\n        } else {\n            cursors.extend(copy_file(src, &dst)?);\n        }\n    }\n    anyhow::ensure!(\n        !cursors.is_empty(),\n        \"could not find any `<CURSOR>` directives in any of the files in `{src_dir}`\",","sourceCodeStart":543,"sourceCodeEnd":579,"githubUrl":"https://github.com/astral-sh/ruff/blob/5bb508f59481c1a02d5c7ff8568b9ffd8a763eef/crates/ty_completion_eval/src/main.rs#L543-L579","documentation":"copy_project copies a truth fixture project and enumerates its entries; SystemPath::from_std_path rejects non-UTF-8 paths, so when a file or subdirectory inside the fixture has a byte-invalid name this anyhow error is returned, since the eval tool only handles UTF-8 paths.","triggerScenarios":"Running an evaluation task whose project fixture directory contains a file or directory with non-UTF-8 bytes in its name; hit during to_tasks -> copy_project while iterating directory entries.","commonSituations":"Archive extraction, symlink weirdness, or a Python/shell script created a file with escaped byte names inside the fixture; copied fixture from a filesystem with non-UTF-8 encoding.","solutions":["Rename or delete the non-UTF-8 entry inside the fixture project directory","Locate it with `find <fixture-dir> | grep -P '[^\\x00-\\x7F]'` or `ls -b <fixture-dir>`","Regenerate the fixture from a clean source rather than copying extracted archives"],"exampleFix":"// before\n$ cp -a ~/Downloads/project_fixture crates/ty_completion_eval/truth/  # contains bad\\xff.py\n// after\n$ find crates/ty_completion_eval/truth/project_fixture -name $'\\xff*' -delete\n$ uv run --package ty_completion_eval -- all --threshold 0.4 ...","handlingStrategy":"validation","validationCode":"fn validate_fixture_utf8(dir: &std::path::Path) -> std::io::Result<()> {\n    for entry in walkdir(dir) {\n        if entry.to_str().is_none() {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidData,\n                format!(\"non-UTF-8 path in fixture: {}\", entry.display()),\n            ));\n        }\n    }\n    Ok(())\n}","typeGuard":"fn all_utf8(dir: &std::path::Path) -> bool {\n    std::fs::read_dir(dir).map(|rd| rd.filter_map(|e| e.ok()).all(|e| e.path().to_str().is_some())).unwrap_or(false)\n}","tryCatchPattern":"match to_tasks(...) {\n    Ok(tasks) => tasks,\n    Err(e) if e.to_string().contains(\"not valid UTF-8\") => {\n        eprintln!(\"rename the non-UTF-8 entry in the fixture: {e}\");\n        std::process::exit(2);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never hand-copy fixtures extracted from archives with raw byte filenames","Scan fixtures with `find | grep -P '[^\\x00-\\x7F]'` before committing","Regenerate fixtures from source control instead of ad-hoc copies"],"tags":["rust","utf-8","filesystem","completion-eval"],"backgroundTag":"invalid-utf8-path","analyzedSha":"5bb508f59481c1a02d5c7ff8568b9ffd8a763eef","analyzedAt":"2026-09-05T10:32:37.492Z","contentChangedAt":"2026-09-05T10:32:37.492Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}