{"record":{"id":"9865b3337605824e","repo":"n0-computer/iroh","slug":"framenotallowedinversion","errorCode":"FrameNotAllowedInVersion","errorMessage":"Received a frame not allowed in this protocol version.","messagePattern":"Received a frame not allowed in this protocol version\\.","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"iroh-relay/src/protos/relay.rs","lineNumber":440,"sourceCode":"            FrameType::EndpointGone => {\n                ensure!(content.len() == EndpointId::LENGTH, Error::InvalidFrame);\n                let endpoint_id = cache.key_from_slice(content.as_ref())?;\n                Self::EndpointGone(endpoint_id)\n            }\n            FrameType::Ping => {\n                ensure!(content.len() == 8, Error::InvalidFrame);\n                let mut data = [0u8; 8];\n                data.copy_from_slice(&content[..8]);\n                Self::Ping(data)\n            }\n            FrameType::Pong => {\n                ensure!(content.len() == 8, Error::InvalidFrame);\n                let mut data = [0u8; 8];\n                data.copy_from_slice(&content[..8]);\n                Self::Pong(data)\n            }\n            FrameType::Health => {\n                ensure!(\n                    protocol_version == ProtocolVersion::V1,\n                    Error::FrameNotAllowedInVersion\n                );\n                let problem = std::str::from_utf8(&content)?.to_owned();\n                Self::Health { problem }\n            }\n            FrameType::Restarting => {\n                ensure!(content.len() == 4 + 4, Error::InvalidFrame);\n                let reconnect_in = u32::from_be_bytes(\n                    content[..4]\n                        .try_into()\n                        .map_err(|_| e!(Error::InvalidFrame))?,\n                );\n                let try_for = u32::from_be_bytes(\n                    content[4..]\n                        .try_into()\n                        .map_err(|_| e!(Error::InvalidFrame))?,\n                );","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/n0-computer/iroh/blob/2b4de030ce5e0133f272871a76f0c685c63f552a/iroh-relay/src/protos/relay.rs#L422-L458","documentation":"A Health frame was received while the negotiated protocol version was not V1. Health frames only exist in protocol version 1; in later versions they are rejected with FrameNotAllowedInVersion because the peer is speaking a frame type foreign to the negotiated version.","triggerScenarios":"Frame::from_bytes decodes FrameType::Health when protocol_version != ProtocolVersion::V1 — e.g. the client negotiated V2+ but the remote still sends legacy Health frames.","commonSituations":"Mixed-version deployments where a newer client connects to an old relay (or vice versa) with mismatched version negotiation, or pinned old crate versions after an upgrade.","solutions":["Upgrade both client and relay to the same iroh-relay version so version negotiation agrees.","If you must support the legacy peer, negotiate ProtocolVersion::V1 for that connection.","Check that no manual frame injection or test harness sends Health frames on V2+ connections.","Inspect the negotiated protocol version in the client handshake logs before decoding frames."],"exampleFix":"// before: always sending Health regardless of version\nconn.send_frame(&Frame::Health { problem: \"overloaded\".into() });\n// after: only on V1\nif protocol_version == ProtocolVersion::V1 {\n    conn.send_frame(&Frame::Health { problem: \"overloaded\".into() });\n} else {\n    conn.send_frame(&Frame::Status(Status::healthy()));\n}","handlingStrategy":"validation","validationCode":"if protocol_version != ProtocolVersion::V1 && frame_type == FrameType::Health {\n    return Err(RelayError::frame_not_allowed_in_version(frame_type, protocol_version));\n}","typeGuard":"fn frame_allowed(ft: FrameType, v: ProtocolVersion) -> bool {\n    match ft {\n        FrameType::Health => v == ProtocolVersion::V1,\n        _ => true,\n    }\n}","tryCatchPattern":"match result {\n    Err(Error::FrameNotAllowedInVersion) => {\n        tracing::warn!(\"peer sent V1-only frame on {protocol_version:?}; upgrading peer required\");\n        negotiate_or_disconnect();\n    }\n    other => other,\n}","preventionTips":["Gate frame sending on the negotiated protocol version","Upgrade all clients and relays together","Add an integration test that runs the highest supported version handshake"],"tags":["network","protocol","versioning"],"backgroundTag":"incompatible-source-type","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"}