{"record":{"id":"f2f82a3c3cda2ef3","repo":"babysor/MockingBird","slug":"invalid-srt-timestamp-value","errorCode":null,"errorMessage":"Invalid SRT timestamp: {value}","messagePattern":"Invalid SRT timestamp: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/speak/scripts/render_timeline.py","lineNumber":61,"sourceCode":"@dataclass\nclass Cue:\n    index: int\n    start_ms: int\n    end_ms: int\n    text: str\n\n    @property\n    def duration_ms(self) -> int:\n        return max(1, self.end_ms - self.start_ms)\n\n\n# ── SRT parsing ──────────────────────────────────────────────────────\n\n\ndef parse_timestamp_ms(value: str) -> int:\n    match = TIMESTAMP_RE.match(value.strip())\n    if not match:\n        raise ValueError(f\"Invalid SRT timestamp: {value}\")\n    hh, mm, ss, ms = map(int, match.groups())\n    return ((hh * 60 + mm) * 60 + ss) * 1000 + ms\n\n\ndef parse_srt(path: Path) -> List[Cue]:\n    content = path.read_text(encoding=\"utf-8\", errors=\"replace\")\n    blocks = re.split(r\"\\n\\s*\\n\", content.strip())\n    cues: List[Cue] = []\n    for block in blocks:\n        lines = [ln.rstrip() for ln in block.splitlines() if ln.strip()]\n        if len(lines) < 3:\n            continue\n        try:\n            idx = int(lines[0])\n        except ValueError:\n            continue\n        if \"-->\" not in lines[1]:\n            continue","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/babysor/MockingBird/blob/28dc5e14f12d7c754612af2fde8e78a4b03f8616/skills/speak/scripts/render_timeline.py#L43-L79","documentation":"ValueError raised by parse_timestamp_ms when an SRT timestamp string does not match the expected HH:MM:SS,mmm pattern (e.g. 00:01:02,345). The regex TIMESTAMP_RE must match before groups are extracted, so malformed timestamps abort parsing.","triggerScenarios":"Timestamps using '.' instead of ',' for milliseconds, missing components (MM:SS), extra spaces, or lines corrupted by encoding issues; also applies to end timestamps in cue ranges.","commonSituations":"SRT files edited by tools that emit period decimal separators, hand-edited files, files converted from VTT without normalization, or read with the wrong encoding.","solutions":["Normalize timestamps: replace '.' with ',' in the ms field before parsing","Fix the offending cue line shown in the message","Re-export the subtitle from the authoring tool with SRT-standard formatting"],"exampleFix":"# before\nstart_ms = parse_timestamp_ms(start_raw)\n# after\nstart_ms = parse_timestamp_ms(start_raw.strip().replace('.', ',') if start_raw.count(':') == 2 else start_raw)","handlingStrategy":"validation","validationCode":"import re\nTIMESTAMP = re.compile(r'^\\d{2,}:\\d{2}:\\d{2}[,.]\\d{3}$')\ndef is_valid_ts(v: str) -> bool:\n    return bool(TIMESTAMP.match(v.strip()))","typeGuard":"def is_valid_timestamp(value: str) -> bool:\n    return bool(re.match(r'^\\d{2,}:\\d{2}:\\d{2},\\d{3}$', value.strip()))","tryCatchPattern":"try:\n    ms = parse_timestamp_ms(raw)\nexcept ValueError:\n    ms = parse_timestamp_ms(raw.replace('.', ','))","preventionTips":["Normalize ms separators before parsing","Use dedicated SRT tooling for authoring","Lint subtitle files in CI"],"tags":["srt","parsing","subtitle","validation"],"backgroundTag":"timestamp-parse-failed","analyzedSha":"28dc5e14f12d7c754612af2fde8e78a4b03f8616","analyzedAt":"2026-08-27T02:26:53.589Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}