Fix #227: 修复可用性监控 15 分钟时间范围的 Invalid Date 错误#231
Conversation
根本原因:前端传递小数形式的 bucketSizeMinutes(如 0.25 表示 15 秒), 但后端使用 parseInt() 解析,导致 0.25 被转换为 0, 在除法运算中产生 Infinity,最终导致 Invalid Date 错误。 修复: - API 路由:使用 parseFloat 代替 parseInt 解析 bucketSizeMinutes - 可用性服务:增加最小值保护(0.25 分钟 = 15 秒)防止除零错误 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Summary of ChangesHello @ding113, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 此拉取请求旨在解决可用性监控页面在特定时间范围选择下出现的渲染故障。通过修正 bucketSizeMinutes 参数的解析逻辑并引入防御性的最小值保护,确保了系统能够正确处理时间桶大小,从而避免了因除零操作导致的 Invalid Date 错误,提升了监控功能的稳定性和用户体验。 Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
🔒 Security Scan Results✅ No security vulnerabilities detected This PR has been scanned against OWASP Top 10, CWE Top 25, and common security anti-patterns. No security issues were identified in the code changes. Changes Analyzed
Scanned Categories
OWASP Top 10 Coverage
🛡️ Security PostureAcceptable - This PR is a bug fix that adds input validation protection. The 🤖 Automated security scan by Claude AI - OWASP Top 10 & CWE coverage |
ding113
left a comment
There was a problem hiding this comment.
📋 Code Review Summary
This PR fixes a division-by-zero bug in the availability monitoring feature by using parseFloat() instead of parseInt() and adding minimum value protection. The fix addresses the root cause correctly. However, there is one issue that should be addressed.
🔍 Issues Found
- Critical (🔴): 0 issues
- High (🟠): 1 issue
- Medium (🟡): 0 issues
- Low (🟢): 0 issues
🎯 Priority Actions
-
🟠 High -
src/app/api/availability/route.ts:55:parseFloat()returnsNaNfor invalid input (e.g.,bucketSizeMinutes=abc), which bypasses the minimum value protection sinceMath.max(0.25, NaN)returnsNaN. This would still cause the original division-by-zero bug with malformed input.Suggested fix:
// Use parseFloat to support sub-minute bucket sizes (e.g., 0.25 for 15 seconds) const parsed = parseFloat(bucketSizeMinutes); // Ensure bucket size is valid and at least 0.25 minutes (15 seconds) to prevent division by zero options.bucketSizeMinutes = Number.isNaN(parsed) ? 0.25 : Math.max(0.25, parsed);
💡 General Observations
The defensive programming approach of adding the minimum value check in both the API route and the service layer is sound. The service layer's protection at availability-service.ts:186 would catch the NaN case if the route is fixed, but it's better to handle invalid input at the API boundary. Consider adding the Number.isNaN() check to both locations for complete defense-in-depth.
🤖 Automated review by Claude AI - focused on identifying issues for improvement
There was a problem hiding this comment.
Code Review
本次 PR 修复了可用性监控页面在选择15分钟时间范围时因 parseInt 错误解析小数而导致的 “Invalid Date” 错误。修改的核心是将 parseInt 替换为 parseFloat,并增加了最小值保护,确保 bucketSizeMinutes 不会为零。整体来看,这是一个正确的修复。我补充了一个建议,用于处理当 bucketSizeMinutes 参数为无效字符串(如 'abc')时 parseFloat 返回 NaN 的边缘情况,以增强代码的健壮性。
src/app/api/availability/route.ts
Outdated
| const parsed = parseFloat(bucketSizeMinutes); | ||
| // Ensure bucket size is at least 0.25 minutes (15 seconds) to prevent division by zero | ||
| options.bucketSizeMinutes = Math.max(0.25, parsed); |
There was a problem hiding this comment.
这里使用 parseFloat 转换查询参数是正确的,但没有处理 parseFloat 可能返回 NaN 的情况(例如,当 bucketSizeMinutes 是一个无效的数字字符串如 'abc' 时)。如果 parsed 是 NaN,Math.max(0.25, NaN) 的结果也是 NaN。这会导致 options.bucketSizeMinutes 被设置为 NaN,并最终在 availability-service.ts 中引发同样的 Invalid time value 错误。
建议在赋值前增加一个 isNaN 检查,以确保只有在解析出有效数字时才设置 bucketSizeMinutes。
const parsed = parseFloat(bucketSizeMinutes);
if (!isNaN(parsed)) {
// Ensure bucket size is at least 0.25 minutes (15 seconds) to prevent division by zero
options.bucketSizeMinutes = Math.max(0.25, parsed);
}- Add Number.isNaN check in route.ts to handle invalid parseFloat input - Add Number.isNaN check in availability-service.ts as defense-in-depth - Fixes edge case where Math.max(0.25, NaN) returns NaN, causing Invalid Date error
🔒 Security Scan Results✅ No security vulnerabilities detected This PR has been scanned against OWASP Top 10, CWE Top 25, and common security anti-patterns. No security issues were identified in the code changes. Scanned Categories
Security Positive FindingsThis PR actually improves the security posture by:
Code Quality NotesThe changes are well-implemented:
🤖 Automated security scan by Claude AI - OWASP Top 10 & CWE coverage |
| options.bucketSizeMinutes = parseInt(bucketSizeMinutes, 10); | ||
| // Use parseFloat to support sub-minute bucket sizes (e.g., 0.25 for 15 seconds) | ||
| const parsed = parseFloat(bucketSizeMinutes); | ||
| // Ensure bucket size is valid and at least 0.25 minutes (15 seconds) to prevent division by zero |
There was a problem hiding this comment.
🟠 High: Missing validation for Infinity input causes the same "Invalid Date" error this PR aims to fix.
Why this is a problem: When a user provides bucketSizeMinutes=Infinity, parseFloat("Infinity") returns Infinity, which passes both the Number.isNaN() check and Math.max(0.25, Infinity). This results in bucketSizeMs = Infinity, and subsequently new Date(Math.floor(reqTime / Infinity) * Infinity) produces an Invalid Date, throwing the same RangeError this PR is intended to fix.
Suggested fix:
// Use parseFloat to support sub-minute bucket sizes (e.g., 0.25 for 15 seconds)
const parsed = parseFloat(bucketSizeMinutes);
// Ensure bucket size is valid, finite, and at least 0.25 minutes (15 seconds) to prevent division by zero
options.bucketSizeMinutes = Number.isFinite(parsed) ? Math.max(0.25, parsed) : 0.25;Using Number.isFinite() instead of !Number.isNaN() will also reject Infinity and -Infinity, providing more robust validation.
| // Handle NaN case (nullish coalescing doesn't catch NaN from invalid parseFloat input) | ||
| const rawBucketSize = | ||
| explicitBucketSize ?? determineOptimalBucketSize(requests.length, timeRangeMinutes); | ||
| const bucketSizeMinutes = Number.isNaN(rawBucketSize) |
There was a problem hiding this comment.
🟠 High: Same Infinity vulnerability exists in the service layer.
Why this is a problem: If explicitBucketSize is Infinity (passed from the route), this code path will accept it since Number.isNaN(Infinity) is false and Math.max(0.25, Infinity) returns Infinity. This leads to the same Invalid Date error.
Suggested fix:
const bucketSizeMinutes = !Number.isFinite(rawBucketSize)
? determineOptimalBucketSize(requests.length, timeRangeMinutes)
: Math.max(0.25, rawBucketSize);Using !Number.isFinite() covers NaN, Infinity, and -Infinity in a single check.
ding113
left a comment
There was a problem hiding this comment.
📋 Code Review Summary
This PR correctly identifies and addresses the root cause of the Invalid Date error when using 15-minute time ranges in the availability monitor. However, the fix is incomplete as it doesn't handle Infinity input values, which can cause the same error.
🔍 Issues Found
- Critical (🔴): 0 issues
- High (🟠): 2 issues
- Medium (🟡): 0 issues
- Low (🟢): 0 issues
🎯 Priority Actions
- Replace
Number.isNaN()withNumber.isFinite()in both files -parseFloat("Infinity")returnsInfinity, which passes theNumber.isNaN()check but still causes Invalid Date errors when used in the bucket calculation.
💡 General Observations
The defensive programming approach with validation in both the API route and service layer is good practice. However, both layers need the same fix: use Number.isFinite() instead of !Number.isNaN() to catch both NaN and Infinity values in a single check.
🤖 Automated review by Claude AI - focused on identifying issues for improvement
Close #227
Summary
bucketSizeMinutes参数被parseInt()错误解析,导致除零错误Root Cause
前端在选择 15 分钟时间范围时,计算出的
bucketSizeMinutes = 0.25(15 秒),但后端 API 使用parseInt("0.25", 10)解析,得到0。在
availability-service.ts中:Changes
src/app/api/availability/route.ts: 使用parseFloat()代替parseInt()解析bucketSizeMinutes,并增加最小值保护src/lib/availability/availability-service.ts: 增加最小值保护(0.25 分钟 = 15 秒),作为防御性编程的双重保险🤖 Generated with Claude Code