EpicGames/lore · warning
hex was not valid utf8
Error message
hex was not valid utf8
What it means
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.
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
Example fix
// before let mut buf = reused_scratch; // may hold stale non-UTF8 bytes let s = to_hex_str(src, &mut buf); // after let mut buf = vec![0u8; src.len() * 2]; // fresh, zeroed let s = to_hex_str(src, &mut buf);
Defensive patterns
Strategy: validation
Validate before calling
fn dst_clean(dst: &[u8]) -> bool { dst.iter().all(|&b| b == 0) } // call on a fresh buffer before to_hex_str Type guard
fn is_ascii_hex(buf: &[u8]) -> bool { buf.iter().all(|b| b.is_ascii_hexdigit()) } Try / catch
match std::panic::catch_unwind(|| to_hex_str(src, &mut buf)) {
Ok(s) => s,
Err(_) => { /* treat as corruption bug; regenerate buffer and retry once */ }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Failed to decode protocol
- hex encode failed
- Failed to open log file
- {e}
- Networking not supported on this OS
AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13).
Data as JSON: /api/errors/84f9aaedb536f75e.
Report an issue: GitHub.
Appendix: source
Thrown at lore-revision/src/util.rs:24
pub mod encoding;
pub mod fs;
pub mod inflight;
pub mod path;
pub mod serde;
pub mod task_queue;
pub mod time;
pub mod url;
/// Provides a mechanism for converting data to a hex `&str` without unnecessary allocations.
/// Note: the `dst` parameter must be passed in in order to give us something to which we can tie
/// the lifetime of the returned &str.
#[inline]
pub fn to_hex_str<'a>(src: &[u8], dst: &'a mut [u8]) -> &'a str {
debug_assert_eq!(dst.len(), src.len() * 2);
// These should never fail, but if it does, we'd rather panic than use a default value
hex::encode_to_slice(src, dst).expect("hex encode failed");
std::str::from_utf8(dst).expect("hex was not valid utf8")
}
View on GitHub (pinned to 074eb0b0d1)