{"record":{"id":"a9922f095d4ae17f","repo":"modelcontextprotocol/servers","slug":"invalid-time-format-expected-hh-mm-24-hour-forma","errorCode":null,"errorMessage":"Invalid time format. Expected HH:MM [24-hour format]","messagePattern":"Invalid time format\\. Expected HH:MM \\[24-hour format\\]","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/time/src/mcp_server_time/server.py","lineNumber":83,"sourceCode":"\n        return TimeResult(\n            timezone=timezone_name,\n            datetime=current_time.isoformat(timespec=\"seconds\"),\n            day_of_week=current_time.strftime(\"%A\"),\n            is_dst=bool(current_time.dst()),\n        )\n\n    def convert_time(\n        self, source_tz: str, time_str: str, target_tz: str\n    ) -> TimeConversionResult:\n        \"\"\"Convert time between timezones\"\"\"\n        source_timezone = get_zoneinfo(source_tz)\n        target_timezone = get_zoneinfo(target_tz)\n\n        try:\n            parsed_time = datetime.strptime(time_str, \"%H:%M\").time()\n        except ValueError:\n            raise ValueError(\"Invalid time format. Expected HH:MM [24-hour format]\")\n\n        now = datetime.now(source_timezone)\n        source_time = datetime(\n            now.year,\n            now.month,\n            now.day,\n            parsed_time.hour,\n            parsed_time.minute,\n            tzinfo=source_timezone,\n        )\n\n        target_time = source_time.astimezone(target_timezone)\n        source_offset = source_time.utcoffset() or timedelta()\n        target_offset = target_time.utcoffset() or timedelta()\n        hours_difference = (target_offset - source_offset).total_seconds() / 3600\n\n        if hours_difference.is_integer():\n            time_diff_str = f\"{hours_difference:+.1f}h\"","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/modelcontextprotocol/servers/blob/76d64c822f5125032f89eb71dbdb94e42b434821/src/time/src/mcp_server_time/server.py#L65-L101","documentation":"convert_time parses time_str with datetime.strptime(time_str, '%H:%M') (server.py:80-83); any strptime ValueError is re-raised as ValueError('Invalid time format. Expected HH:MM [24-hour format]'). Only 24-hour HH:MM is accepted (12-hour, AM/PM, seconds, out-of-range, and empty strings are rejected). Like errors 44/46/47/48, the outer handler (error 49) re-wraps this before it leaves the server.","triggerScenarios":"Passing '2:30 PM', '14:30:00', '09:00 AM', '25:00', 'noon', or '' as the 'time' argument.","commonSituations":"12-hour habits, natural-language times from an LLM ('2pm'), locale-formatted strings, or a stray seconds component.","solutions":["Send exactly zero-padded 24-hour HH:MM (e.g. '14:30', '09:05').","Normalize client-side: parse the user's input, then re-emit strftime('%H:%M').","Reject empty or None before constructing the call."],"exampleFix":"// before\n//   time: \"2:30 PM\"   -> Invalid time format\n// after\n//   time: \"14:30\"","handlingStrategy":"validation","validationCode":"from datetime import datetime\n\ndef normalize_hhmm(s: str) -> str:\n    # raises ValueError if not parseable as 24-hour HH:MM\n    return datetime.strptime(s, \"%H:%M\").strftime(\"%H:%M\")\n\ntime_str = normalize_hhmm(arguments[\"time\"])","typeGuard":"import re\n\ndef is_hhmm(v: object) -> bool:\n    return isinstance(v, str) and bool(re.fullmatch(r\"([01]\\d|2[0-3]):[0-5]\\d\", v))","tryCatchPattern":null,"preventionTips":["Format every time to %H:%M at the trust boundary.","Reject 12-hour/AM-PM/seconds upstream before constructing the call.","Feed natural-language times through a parser that emits HH:MM."],"tags":["time","format","validation","python"],"backgroundTag":null,"analyzedSha":"76d64c822f5125032f89eb71dbdb94e42b434821","analyzedAt":"2026-08-12T10:02:41.718Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}