{"record":{"id":"ac8fcca94fc55458","repo":"sansan0/TrendRadar","slug":"data-not-found","errorCode":"DATA_NOT_FOUND","errorMessage":"未找到包含关键词 '{keyword}' 的新闻","messagePattern":"未找到包含关键词 '(.+?)' 的新闻","errorType":"error_code","errorClass":"DataNotFoundError","httpStatus":null,"severity":"error","filePath":"mcp_server/services/data_service.py","lineNumber":273,"sourceCode":"                                \"ranks\": info[\"ranks\"],\n                                \"count\": len(info[\"ranks\"]),\n                                \"avg_rank\": round(avg_rank, 2),\n                                \"url\": info.get(\"url\", \"\"),\n                                \"mobileUrl\": info.get(\"mobileUrl\", \"\"),\n                                \"date\": current_date.strftime(\"%Y-%m-%d\")\n                            })\n\n                            platform_distribution[platform_id] += 1\n\n            except DataNotFoundError:\n                # 该日期没有数据,继续下一天\n                pass\n\n            # 下一天\n            current_date += timedelta(days=1)\n\n        if not results:\n            raise DataNotFoundError(\n                f\"未找到包含关键词 '{keyword}' 的新闻\",\n                suggestion=\"请尝试其他关键词或扩大日期范围\"\n            )\n\n        # 计算统计信息\n        total_ranks = []\n        for item in results:\n            total_ranks.extend(item[\"ranks\"])\n\n        avg_rank = sum(total_ranks) / len(total_ranks) if total_ranks else 0\n\n        # 限制返回数量(如果指定)\n        total_found = len(results)\n        if limit is not None and limit > 0:\n            results = results[:limit]\n\n        return {\n            \"results\": results,","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/sansan0/TrendRadar/blob/8ee26026ba6c11dec41a95fb3895a7162876caa1/mcp_server/services/data_service.py#L255-L291","documentation":"Raised by Scheduler._validate_hhmm after the HH:MM shape check passes but the numeric values are out of range: hour must be 0-23 and minute 0-59. The regex only enforces two digits, so '25:70' is shape-valid but semantically invalid, and this second ValueError fires. It indicates a well-formatted but impossible clock time in scheduler config.","triggerScenarios":"Calling _validate_hhmm (directly or via scheduler config validation) with values such as '24:00' (use '00:00' for midnight), '25:30' (hour > 23), '09:60' or '12:99' (minute > 59). Arithmetic on times that carries past bounds, e.g. computing end = start + duration and producing '23:90', also triggers it.","commonSituations":"Config authored with '24:00' intending end-of-day; wrap-around windows like 22:00-26:00 written literally instead of 22:00-02:00; time arithmetic in generating scripts that does not modulo the hour/minute; copy-paste of military/local 24h+ conventions.","solutions":["Correct the value: hours 0-23, minutes 0-59. Replace '24:00' with '00:00'.","For windows crossing midnight, split into two windows or use the library's supported overnight representation instead of inflating the hour (e.g. 22:00-02:00, not 22:00-26:00).","If computing times programmatically, normalize with divmod: h, m = divmod(total_minutes, 60); h %= 24 before formatting.","Validate config with a stricter regex '^([01]\\d|2[0-3]):[0-5]\\d$' upfront to catch range errors at load time."],"exampleFix":"# before\nwindow = {\"start\": \"22:00\", \"end\": \"24:30\"}\n\n# after\nwindow = {\"start\": \"22:00\", \"end\": \"00:30\"}  # crosses midnight\n\n# normalize computed times\ntotal = 25 * 60 + 70\nh, m = divmod(total, 60)\nh %= 60  # wrap hours into 0-23 after adding minutes\nvalue = f\"{h % 24:02d}:{m:02d}\"","handlingStrategy":"validation","validationCode":"def is_valid_hhmm(value: str) -> bool:\n    \"\"\"Shape AND range: HH 00-23, MM 00-59.\"\"\"\n    if not re.match(r\"^\\d{2}:\\d{2}$\", value):\n        return False\n    h, m = int(value[:2]), int(value[3:])\n    return 0 <= h <= 23 and 0 <= m <= 59\n\nassert all(is_valid_hhmm(t) for t in config[\"quiet_hours\"].values())","typeGuard":"def is_valid_hhmm(value: str) -> bool:\n    if not isinstance(value, str) or not re.match(r\"^\\d{2}:\\d{2}$\", value):\n        return False\n    h, m = int(value[:2]), int(value[3:])\n    return 0 <= h <= 23 and 0 <= m <= 59","tryCatchPattern":null,"preventionTips":["Never encode 'end of day' as 24:xx — use 00:00 and split overnight windows.","After any time arithmetic, normalize with divmod(minutes, 60) and h %= 24 before formatting.","Use one stricter regex '^([01]\\\\d|2[0-3]):[0-5]\\\\d$' in config validation to reject both shape and range errors at once."],"tags":["scheduler","validation","time-range","config"],"backgroundTag":null,"analyzedSha":"8ee26026ba6c11dec41a95fb3895a7162876caa1","analyzedAt":"2026-08-15T01:42:18.084Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}