{"record":{"id":"84f9aaedb536f75e","repo":"EpicGames/lore","slug":"hex-was-not-valid-utf8","errorCode":null,"errorMessage":"hex was not valid utf8","messagePattern":"hex was not valid utf8","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"lore-revision/src/util.rs","lineNumber":24,"sourceCode":"pub mod encoding;\npub mod fs;\npub mod inflight;\npub mod path;\npub mod serde;\npub mod task_queue;\npub mod time;\npub mod url;\n\n/// Provides a mechanism for converting data to a hex `&str` without unnecessary allocations.\n/// Note: the `dst` parameter must be passed in in order to give us something to which we can tie\n///     the lifetime of the returned &str.\n#[inline]\npub fn to_hex_str<'a>(src: &[u8], dst: &'a mut [u8]) -> &'a str {\n    debug_assert_eq!(dst.len(), src.len() * 2);\n\n    // These should never fail, but if it does, we'd rather panic than use a default value\n    hex::encode_to_slice(src, dst).expect(\"hex encode failed\");\n    std::str::from_utf8(dst).expect(\"hex was not valid utf8\")\n}\n","sourceCodeStart":6,"sourceCodeEnd":26,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-revision/src/util.rs#L6-L26","documentation":"After hex-encoding into dst, to_hex_str converts dst to &str with str::from_utf8 and panics if the bytes are not valid UTF-8. Since hex::encode_to_slice only writes ASCII hex digits, this expect is unreachable when the encode step succeeded on the intended buffer; it fires if dst already contained non-UTF-8 bytes that encode_to_slice did not overwrite (partial write) or is otherwise corrupted.","triggerScenarios":"Effectively only when the preceding hex::encode_to_slice did not fill the whole buffer (e.g. panic-free misuse, custom hex versions) leaving stale non-UTF-8 bytes in dst, or if encode wrote nothing due to empty/edge-case misuse combined with pre-filled invalid bytes.","commonSituations":"Buffer reuse across calls where a prior failed encode left garbage, or a vendored/patched hex crate whose error paths differ from expectations. In practice developers hit this via the sibling 'hex encode failed' panic; this one indicates deeper memory/buffer corruption.","solutions":["Treat this panic as a bug report: verify dst is zero-initialized before calling to_hex_str","Ensure the preceding 'hex encode failed' panic is not being masked; fix the buffer length first","Always pass a freshly allocated buffer rather than a reused one","If you control the code, prefer hex::encode to return an owned String and remove the two expects"],"exampleFix":"// before\nlet mut buf = reused_scratch; // may hold stale non-UTF8 bytes\nlet s = to_hex_str(src, &mut buf);\n// after\nlet mut buf = vec![0u8; src.len() * 2]; // fresh, zeroed\nlet s = to_hex_str(src, &mut buf);","handlingStrategy":"validation","validationCode":"fn dst_clean(dst: &[u8]) -> bool { dst.iter().all(|&b| b == 0) } // call on a fresh buffer before to_hex_str","typeGuard":"fn is_ascii_hex(buf: &[u8]) -> bool { buf.iter().all(|b| b.is_ascii_hexdigit()) }","tryCatchPattern":"match std::panic::catch_unwind(|| to_hex_str(src, &mut buf)) {\n    Ok(s) => s,\n    Err(_) => { /* treat as corruption bug; regenerate buffer and retry once */ }\n}","preventionTips":["Never reuse scratch buffers for hex output; allocate fresh zeroed buffers","Fix buffer-length bugs first — this panic usually trails the 'hex encode failed' one","Keep hex crate versions pinned and reviewed","Replace the double-expect helper with hex::encode in new code"],"tags":["rust","utf8","hex","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"074eb0b0d1194c997d7cf28b55519e3e197b3e23","analyzedAt":"2026-09-13T09:00:57.509Z","contentChangedAt":"2026-09-13T09:00:57.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}