{"record":{"id":"32b70758466a355a","repo":"EpicGames/lore","slug":"hex-encode-failed","errorCode":null,"errorMessage":"hex encode failed","messagePattern":"hex encode failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lore-revision/src/util.rs","lineNumber":23,"sourceCode":"pub mod config;\npub 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":5,"sourceCodeEnd":26,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-revision/src/util.rs#L5-L26","documentation":"to_hex_str encodes src into the caller-provided dst buffer with hex::encode_to_slice and panics via .expect if the encoding fails. The function's contract (debug_assert dst.len() == src.len()*2) means this should be impossible; the panic is a deliberate fail-fast instead of silently returning wrong data. It fires only when the output buffer is too small for the hex representation.","triggerScenarios":"Calling to_hex_str with a dst slice shorter than src.len()*2 (in release builds, where the debug_assert is compiled out, encode_to_slice returns Err(FromHexError::InvalidStringLength) and the expect panics).","commonSituations":"A caller sized the buffer from a wrong constant (e.g. hash length changed from 16 to 32 bytes after a version change), reused a buffer sized for a different identifier, or computed dst length as src.len() instead of src.len()*2.","solutions":["Size dst as exactly src.len()*2 bytes before calling","If the input length changed (e.g. digest size), update every buffer sizing constant together","Use a fixed-size helper or const-generic buffer to keep src and dst lengths in sync","Optionally replace with hex::encode_into reusing an owned String to eliminate buffer sizing entirely"],"exampleFix":"// before\nlet mut buf = [0u8; 32]; // sized for 16-byte src\nlet s = to_hex_str(&digest, &mut buf); // digest is 32 bytes -> panic\n// after\nlet mut buf = [0u8; 64]; // digest.len() * 2\nlet s = to_hex_str(&digest, &mut buf);","handlingStrategy":"validation","validationCode":"fn hex_buffer_ok(src: &[u8], dst: &[u8]) -> bool { dst.len() == src.len() * 2 }","typeGuard":"fn sized_hex_buf<const N: usize>(src: &[u8]) -> Option<[u8; N]> {\n    (N == src.len() * 2).then(|| [0u8; N])\n}","tryCatchPattern":null,"preventionTips":["Always allocate hex buffers as src.len()*2 or with fixed-size arrays tied to the digest constant","Use const generics or newtypes encoding the digest length to keep sizes in sync","Prefer hex::encode returning an owned String when buffer reuse is not required","Add a unit test for every digest length constant change"],"tags":["rust","hex","buffer-size","panic"],"backgroundTag":"invalid-argument-format","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"}