{"record":{"id":"978688027b9b3faa","repo":"NationalSecurityAgency/ghidra","slug":"schedule-must-be-in-form-snap-steps-got-s","errorCode":null,"errorMessage":"Schedule must be in form [snap]:[steps]. Got '{s}'","messagePattern":"Schedule must be in form \\[snap\\]:\\[steps\\]\\. Got '(.+?)'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py","lineNumber":157,"sourceCode":"\n    Until we have need more capable schedules here, we'll just keep it\n    at this. TODO: We might need another flag to indicate the kind of\n    steps here. It seems in Microsoft TTD, it's the number of\n    instructions executed since the last event. However, in rr/gdb, it\n    seems it's the number of branch instructions encountered.\n    \"\"\"\n    snap: int\n    steps: int = 0\n\n    @staticmethod\n    def parse(s: str) -> 'Schedule':\n        parts = s.split(':')\n        if len(parts) == 1:\n            return Schedule(int(parts[0]))\n        elif len(parts) == 2:\n            return Schedule(int(parts[0]), int(parts[1]))\n        else:\n            raise ValueError(\n                f\"Schedule must be in form [snap]:[steps]. Got '{s}'\")\n\n    def __str__(self) -> str:\n        if self.steps == 0:\n            return f\"{self.snap}\"\n        return f\"{self.snap}:{self.steps}\"\n\n\n@dataclass(frozen=True)\nclass DetachedObject:\n    id: int\n    path: str\n\n\n@dataclass(frozen=True)\nclass TraceObject:\n    \"\"\"A proxy for a TraceObject.\"\"\"\n    trace: 'Trace'","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py#L139-L175","documentation":"Raised by Schedule.parse() when the input string contains more than one colon, i.e. it cannot be split into a [snap] or [snap]:[steps] pair. The Schedule dataclass represents a position in a trace as a snapshot id plus an optional step count. Note that non-numeric parts like 'abc' hit int() first and raise a different ValueError, so this specific message only fires on inputs with 3+ colon-separated parts.","triggerScenarios":"Calling Schedule.parse('1:2:3'), Schedule.parse('a:b:c:d'), or passing a snapshot path/range string that contains multiple colons. Any caller that forwards unvalidated user or file-derived text into parse() reaches this branch.","commonSituations":"Pasting a schedule from a UI that formats it as 'snap:steps:extra', reading a malformed config/script argument, or a debugger front-end that passes a full timestamp or address-range string where a bare schedule is expected.","solutions":["Strip/normalize the input to a single optional colon before calling parse: pre-split on ':' and reject early if len != 1 or 2.","Validate with a regex like ^\\d+(:\\d+)?$ before calling parse so the error never reaches the library.","Wrap parse() in try/except ValueError and report the offending value back to the user rather than letting it surface raw."],"exampleFix":"// before\nsched = Schedule.parse(user_input)\n// after\nimport re\nif not re.fullmatch(r'\\d+(:\\d+)?', user_input.strip()):\n    raise ValueError(f'Expected [snap]:[steps], got {user_input!r}')\nsched = Schedule.parse(user_input.strip())","handlingStrategy":"validation","validationCode":"import re\nassert isinstance(s, str)\nif not re.fullmatch(r'\\d+(:\\d+)?', s.strip()):\n    raise ValueError(f'Bad schedule {s!r}; expected [snap]:[steps]')","typeGuard":"def is_schedule_str(s) -> bool:\n    import re\n    return isinstance(s, str) and bool(re.fullmatch(r'\\d+(:\\d+)?', s.strip()))","tryCatchPattern":"try:\n    sched = Schedule.parse(raw)\nexcept ValueError:\n    # report to user, fall back, or re-raise with context\n    raise","preventionTips":["Validate schedule strings at the UI/config boundary.","Always source schedules from a single normalized constant or parser."],"tags":["validation","trace-rmi","input-parsing"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}