{"record":{"id":"5e6df38c9356d7de","repo":"n0-computer/iroh","slug":"invalidframe","errorCode":"InvalidFrame","errorMessage":"Invalid frame encoding","messagePattern":"Invalid frame encoding","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"iroh-relay/src/protos/relay.rs","lineNumber":163,"sourceCode":"impl Status {\n    #[cfg(feature = \"server\")]\n    fn write_to<O: BufMut>(&self, mut dst: O) -> O {\n        match self {\n            Status::Healthy => dst.put_u8(0),\n            Status::SameEndpointIdConnected => dst.put_u8(1),\n            Status::RateLimited => dst.put_u8(2),\n            Status::Unknown(discriminant) => dst.put_u8(*discriminant),\n        }\n        dst\n    }\n\n    #[cfg(feature = \"server\")]\n    fn encoded_len(&self) -> usize {\n        1\n    }\n\n    fn from_bytes(mut bytes: Bytes) -> Result<Self, Error> {\n        ensure!(!bytes.is_empty(), Error::InvalidFrame);\n        let discriminant = bytes.get_u8();\n        match discriminant {\n            0 => Ok(Self::Healthy),\n            1 => Ok(Self::SameEndpointIdConnected),\n            2 => Ok(Self::RateLimited),\n            n => Ok(Self::Unknown(n)),\n        }\n    }\n}\n\n/// Messages that clients send to relays.\n#[derive(Debug, Clone, PartialEq, Eq)]\n#[non_exhaustive]\npub enum ClientToRelayMsg {\n    /// Request from the client to the server to reply to the\n    /// other side with a [`RelayToClientMsg::Pong`] with the given payload.\n    Ping([u8; 8]),\n    /// Reply to a [`RelayToClientMsg::Ping`] from a server","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/n0-computer/iroh/blob/2b4de030ce5e0133f272871a76f0c685c63f552a/iroh-relay/src/protos/relay.rs#L145-L181","documentation":"Error::InvalidFrame from ServerToClientUrlOrEndpoint (health/status) frame decoding: from_bytes requires at least one byte to read the discriminant. An empty buffer cannot encode any health frame, so decoding fails immediately.","triggerScenarios":"Decoding an empty Bytes buffer as a relay health/status frame — e.g. a zero-length message received from the relay or a caller slicing out an empty payload.","commonSituations":"Relay connection closing and delivering a truncated/empty final message; slicing bugs that pass an empty byte slice to from_bytes.","solutions":["Check bytes.is_empty() before calling from_bytes and treat empty input as end-of-stream rather than a frame.","Verify the framing layer reads the declared frame length fully before decoding.","Inspect relay connectivity — repeated empty frames suggest a broken or closed connection."],"exampleFix":"// before\nlet frame = HealthFrame::from_bytes(bytes)?;\n\n// after\nif bytes.is_empty() {\n    return Ok(None); // end of stream / no frame\n}\nlet frame = HealthFrame::from_bytes(bytes)?;","handlingStrategy":"validation","validationCode":"fn decode_health(bytes: &Bytes) -> Option<HealthFrame> {\n    if bytes.is_empty() { return None; }\n    Some(HealthFrame::from_bytes(bytes.clone()).ok()?)\n}","typeGuard":"fn has_frame(bytes: &Bytes) -> bool { !bytes.is_empty() }","tryCatchPattern":null,"preventionTips":["Treat empty payloads as end-of-stream, not frames.","Read the full declared frame length before decoding.","Monitor for repeated empty frames — usually a closing connection."],"tags":["network","protocol","decoding","iroh"],"backgroundTag":"protobuf-unmarshal-failed","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"}