{"record":{"id":"e512a6cebd131b89","repo":"NationalSecurityAgency/ghidra","slug":"min-cannot-exceed-max","errorCode":null,"errorMessage":"min cannot exceed max","messagePattern":"min cannot exceed max","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py","lineNumber":120,"sourceCode":"        return self.max - self.min + 1\n\n\nLIFESPAN_MIN = -1 << 63\nLIFESPAN_MAX = (1 << 63) - 1\n\n\n@dataclass(frozen=True)\nclass Lifespan:\n    min: int = LIFESPAN_MIN\n    max: int = LIFESPAN_MAX\n\n    def __post_init__(self) -> None:\n        if self.min < LIFESPAN_MIN:\n            raise ValueError(\"min out of range of int64\")\n        if self.max > LIFESPAN_MAX:\n            raise ValueError(\"max out of range of int64\")\n        if self.min > self.max and not (self.min == 0 and self.max == -1):\n            raise ValueError(\"min cannot exceed max\")\n\n    def is_empty(self) -> bool:\n        return self.min == 0 and self.max == -1\n\n    def __str__(self) -> str:\n        if self.is_empty():\n            return \"(EMPTY)\"\n        min = '(-inf' if self.min == LIFESPAN_MIN else f'[{self.min}'\n        max = '+inf)' if self.max == LIFESPAN_MAX else f'{self.max}]'\n        return f'{min},{max}'\n\n    def __repr__(self) -> str:\n        return 'Lifespan' + self.__str__()\n\n\n@dataclass\nclass Schedule:\n    \"\"\"A more constrained form of TraceSchedule from our Java code.","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py#L102-L138","documentation":"Thrown by the Python ghidratrace Lifespan dataclass's __post_init__ when min > max, except for the special empty-span case (min == 0 and max == -1) which represents an empty Lifespan. A span where the lower bound exceeds the upper bound is logically invalid.","triggerScenarios":"Constructing Lifespan(min=a, max=b) with a > b (and not the (0, -1) empty case), e.g. swapping min/max arguments or computing a range that inverted.","commonSituations":"Argument order swapped (max passed as min); start/end snaps computed such that start > end; off-by-one in schedule parsing producing an inverted range.","solutions":["Order the bounds so min <= max when constructing, or use the explicit empty span Lifespan(0, -1) for empty.","If bounds may arrive in either order, normalize: mn, mx = sorted([a, b]).","Use the is_empty() idiom (0, -1) deliberately rather than passing an arbitrary inverted pair."],"exampleFix":"# before\nspan = Lifespan(min=end_snap, max=start_snap)  # swapped\n\n# after\nmn, mx = min(start_snap, end_snap), max(start_snap, end_snap)\nspan = Lifespan(min=mn, max=mx)","handlingStrategy":"validation","validationCode":"mn, mx = min(start, end), max(start, end)\nspan = Lifespan(min=mn, max=mx)","typeGuard":"def ordered(mn: int, mx: int) -> bool:\n    return mn <= mx or (mn == 0 and mx == -1)","tryCatchPattern":"try:\n    span = Lifespan(min=lo, max=hi)\nexcept ValueError:\n    lo, hi = min(lo, hi), max(lo, hi)\n    span = Lifespan(min=lo, max=hi)","preventionTips":["Normalize bounds so min <= max before constructing Lifespan.","Use Lifespan(0, -1) deliberately to represent the empty span.","Double-check argument order: min first, max second."],"tags":["python","lifespan","validation","trace-rmi"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}