{"record":{"id":"16af108b6d8c757b","repo":"neondatabase/neon","slug":"non-overlappinng-bounds-self-max-was-less-th","errorCode":null,"errorMessage":"Non-overlappinng bounds: self.max = {} was less than other.min = {}","messagePattern":"Non-overlappinng bounds: self\\.max = (.+?) was less than other\\.min = (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"libs/vm_monitor/src/protocol.rs","lineNumber":225,"sourceCode":"            f.write_fmt(format_args!(\"{} to {}\", self.min, self.max))\n        }\n    }\n}\n\nimpl ProtocolRange {\n    /// Find the highest shared version between two `ProtocolRange`'s\n    pub fn highest_shared_version(&self, other: &Self) -> anyhow::Result<ProtocolVersion> {\n        // We first have to make sure the ranges are overlapping. Once we know\n        // this, we can merge the ranges by taking the max of the mins and the\n        // mins of the maxes.\n        if self.min > other.max {\n            anyhow::bail!(\n                \"Non-overlapping bounds: other.max = {} was less than self.min = {}\",\n                other.max,\n                self.min,\n            )\n        } else if self.max < other.min {\n            anyhow::bail!(\n                \"Non-overlappinng bounds: self.max = {} was less than other.min = {}\",\n                self.max,\n                other.min\n            )\n        } else {\n            Ok(cmp::min(self.max, other.max))\n        }\n    }\n}\n\n/// We send this to the monitor after negotiating which protocol to use\n#[derive(Serialize, Debug)]\n#[serde(rename_all = \"camelCase\")]\npub enum ProtocolResponse {\n    Error(String),\n    Version(ProtocolVersion),\n}\n","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/vm_monitor/src/protocol.rs#L207-L243","documentation":"Mirror case of `ProtocolRange::highest_shared_version`: bails when `self.max < other.min`, i.e. this side's highest known version is below the peer's lowest acceptable version, so the ranges cannot overlap. Note the message contains a typo ('Non-overlappinng') — log greps must match the misspelling.","triggerScenarios":"Calling `highest_shared_version(&other)` where the peer demands a minimum version above this side's maximum — e.g. an upgraded agent with PROTOCOL_MIN_VERSION v2.0 talking to a monitor that only knows up to v1.0.","commonSituations":"Rolling upgrades where the new peer's minimum jumped past the old side's maximum; protocol constants drift between builds; tests with disjoint hardcoded ranges.","solutions":["Upgrade this component (the one whose max is too low) to a build supporting the peer's minimum version","Or have the peer lower its minimum protocol version until this side catches up","Grep logs for 'Non-overlappinng' (sic) and 'Non-overlapping' — both spellings occur on the two sides of the check","Print both ProtocolRange values at handshake to confirm which pair is disjoint"],"exampleFix":"// before: peer requires >= v2.0, we only know up to v1.0\nlet my_range = ProtocolRange { min: PROTOCOL_MIN_VERSION, max: PROTOCOL_MAX_VERSION }; // v1.0..v1.0\nmy_range.highest_shared_version(&peer_min_v2_range)?; // bails: self.max < other.min\n\n// after: upgrade so this side's max covers the peer's min\nlet my_range = ProtocolRange { min: PROTOCOL_MIN_VERSION, max: ProtocolVersion::V2_0 };\nmy_range.highest_shared_version(&peer_min_v2_range)?; // Ok(v2.0)","handlingStrategy":"validation","validationCode":"fn ranges_overlap(a: &ProtocolRange, b: &ProtocolRange) -> bool {\n    a.min <= b.max && a.max >= b.min\n}\n\nif !ranges_overlap(&my_range, &peer_range) {\n    anyhow::bail!(\"peer requires {}, we only support up to {}\", peer_range.min, my_range.max);\n}","typeGuard":"fn ranges_overlap(a: &ProtocolRange, b: &ProtocolRange) -> bool {\n    a.min <= b.max && a.max >= b.min\n}","tryCatchPattern":null,"preventionTips":["Roll out protocol bumps so each side's max always covers the other's current min","Grep for both 'Non-overlapping' and the misspelled 'Non-overlappinng' when searching logs","Include a version-skew integration test between oldest and newest supported builds"],"tags":["rust","neon","vm-monitor","protocol","version-negotiation"],"backgroundTag":"protocol-version-mismatch","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}