{"record":{"id":"c73c5837355cd63a","repo":"GitoxideLabs/gitoxide","slug":"valid-ascii","errorCode":null,"errorMessage":"valid ASCII","messagePattern":"valid ASCII","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"info","filePath":"gitoxide-core/src/repository/status.rs","lineNumber":229,"sourceCode":"\n    progress.init(Some(out.worktree_index.entries().len()), gix::progress::count(\"files\"));\n    progress.set(out.worktree_index.entries().len());\n    progress.show_throughput(start);\n    Ok(())\n}\n\nfn print_index_entry_status(\n    out: &mut dyn std::io::Write,\n    prefix: &Path,\n    rela_path: &BStr,\n    status: EntryStatus<(), gix::submodule::Status>,\n) -> std::io::Result<()> {\n    let char_storage;\n    let status = match status {\n        EntryStatus::Conflict { summary, entries: _ } => as_str(summary),\n        EntryStatus::Change(change) => {\n            char_storage = change_to_char(&change);\n            std::str::from_utf8(std::slice::from_ref(&char_storage)).expect(\"valid ASCII\")\n        }\n        EntryStatus::NeedsUpdate(_stat) => {\n            return Ok(());\n        }\n        EntryStatus::IntentToAdd => \"A\",\n    };\n\n    let rela_path = gix::path::from_bstr(rela_path);\n    let display_path = gix::path::relativize_with_prefix(&rela_path, prefix);\n    writeln!(out, \"{status: >3} {}\", display_path.display())\n}\n\nfn as_str(c: Conflict) -> &'static str {\n    match c {\n        Conflict::BothDeleted => \"DD\",\n        Conflict::AddedByUs => \"AU\",\n        Conflict::DeletedByThem => \"UD\",\n        Conflict::AddedByThem => \"UA\",","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gitoxide-core/src/repository/status.rs#L211-L247","documentation":"When printing index entry status, a change is mapped to a single status character which is converted to `&str` via `str::from_utf8` with an `.expect(\"valid ASCII\")`. Since `change_to_char` only yields ASCII characters, this panics only if that invariant is broken by a future code change.","triggerScenarios":"Calling `print_index_entry_status` (from `show`) where `change_to_char` returns a non-ASCII byte — currently unreachable; a regression in `change_to_char` would trigger it.","commonSituations":"None in practice for library users; only developers modifying the status-character mapping in gitoxide-core could hit this.","solutions":["Verify `change_to_char` only returns ASCII status characters ('A', 'M', 'D', etc.).","Refactor to return `char` or a static `&'static str` from `change_to_char` so the UTF-8 conversion cannot fail.","If hit, inspect the byte value returned and fix the mapping table."],"exampleFix":"// before\nlet char_storage = change_to_char(&change);\nstd::str::from_utf8(std::slice::from_ref(&char_storage)).expect(\"valid ASCII\")\n\n// after\nfn change_to_char(c: &Change) -> &'static str { /* ... */ }\nchange_to_char(&change)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn is_ascii(b: &u8) -> bool { *b < 0x80 }\n// assert change_to_char output is ASCII before conversion","tryCatchPattern":"// unreachable by design; refactor instead\nchange_to_char(&change) // return &'static str directly","preventionTips":["Return &'static str or char from change_to_char to make conversion infallible","Add a unit test asserting all mapped status chars are ASCII","Avoid str::from_utf8 on dynamically derived single bytes without a check"],"tags":["panic","invariant","ascii","status"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}