{"record":{"id":"3aef3f1c67b36cc8","repo":"n0-computer/iroh","slug":"data-length-checked-above","errorCode":null,"errorMessage":"data length checked above","messagePattern":"data length checked above","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"info","filePath":"iroh-base/src/endpoint_addr.rs","lineNumber":380,"sourceCode":"\n    /// Serializes to the binary encoding.\n    ///\n    /// See [`CustomAddr`] docs for details on the encoding.\n    pub fn to_vec(&self) -> Vec<u8> {\n        let mut out = vec![0u8; 8 + self.data.len()];\n        out[..8].copy_from_slice(&self.id().to_le_bytes());\n        out[8..].copy_from_slice(self.data());\n        out\n    }\n\n    /// Parses from the binary encoding.\n    ///\n    /// See [`CustomAddr`] docs for details on the encoding.\n    pub fn from_bytes(data: &[u8]) -> Result<Self, &'static str> {\n        if data.len() < 8 {\n            return Err(\"data too short\");\n        }\n        let id = u64::from_le_bytes(data[..8].try_into().expect(\"data length checked above\"));\n        let data = &data[8..];\n        Ok(Self::from_parts(id, data))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]\n    #[non_exhaustive]\n    enum NewAddrType {\n        /// Relays\n        Relay(RelayUrl),\n        /// IP based addresses\n        Ip(SocketAddr),\n        /// New addr type for testing\n        Cool(u16),","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/n0-computer/iroh/blob/2b4de030ce5e0133f272871a76f0c685c63f552a/iroh-base/src/endpoint_addr.rs#L362-L398","documentation":"CustomAddr::from_bytes first checks `data.len() < 8` and returns \"data too short\"; after that check it slices the first 8 bytes and converts them with try_into().expect(\"data length checked above\"). The panic is an internal invariant: it can only fire if the length check above was bypassed, so it documents that the slice is guaranteed to be exactly 8 bytes at that point.","triggerScenarios":"Not reachable through normal execution: the preceding `if data.len() < 8 { return Err(\"data too short\") }` guarantees the 8-byte slice succeeds. Only reachable if the code is modified so the guard no longer precedes the try_into.","commonSituations":"Developers encounter this string only while reading or refactoring the source; a panic here at runtime would indicate a code regression where the length guard was moved or removed.","solutions":["No action needed at runtime — the guard above always runs first; treat the expect as documentation of the invariant.","If refactoring from_bytes, keep the `data.len() < 8` early-return immediately before the `data[..8].try_into()` call.","Prefer a non-panicking rewrite (match on try_into) if you remove the early return."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Caller-side: from_bytes already returns Result, so handle the 'data too short' case\nfn parse_custom_addr(bytes: &[u8]) -> Result<CustomAddr, String> {\n    if bytes.len() < 8 { return Err(format!(\"need >= 8 bytes, got {}\", bytes.len())); }\n    CustomAddr::from_bytes(bytes).map_err(|e| e.to_string())\n}","typeGuard":null,"tryCatchPattern":"// The function returns Result, not panics — match on it\nmatch CustomAddr::from_bytes(&buf) {\n    Ok(addr) => use_addr(addr),\n    Err(\"data too short\") => warn(\"truncated CustomAddr payload\"),\n    Err(e) => warn(\"CustomAddr decode failed: {e}\"),\n}","preventionTips":["Always check encoded payloads are at least 8 bytes before calling from_bytes.","Preserve the length guard immediately above the try_into when refactoring.","Add a unit test feeding a 7-byte slice to keep the guard covered."],"tags":["internal-invariant","parsing","panic-guard"],"backgroundTag":"internal-invariant-violation","analyzedSha":"2b4de030ce5e0133f272871a76f0c685c63f552a","analyzedAt":"2026-09-08T04:26:47.755Z","contentChangedAt":"2026-09-08T04:26:47.755Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}