📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

适用版本: 6.8-7.15

1. 错误异常的基本描述 #

invalid time hour value [n] (possible values may be between 0 and 23 incl.) 是 Elasticsearch 在解析时间表达式(常见于 Watcher 的 trigger 调度配置)时抛出的异常。该错误表示 hour 字段已被成功解析为数字,但数值不在 0 到 23 的合法范围内。

常见现象 #

  • 创建或更新 Watcher 时返回 400 Bad Request,响应体中包含上述错误信息。
  • Watcher 无法注册,_watcher/stats 接口显示对应 watch 处于 failed 状态。
  • Elasticsearch 日志中出现类似如下记录:
ElasticsearchParseException: invalid time hour value [24] (possible values may be between 0 and 23 incl.)
    at org.elasticsearch.xpack.watcher.trigger.schedule.DayTimes.validHour(DayTimes.java)
    at org.elasticsearch.xpack.watcher.trigger.schedule.CronSchedule.parse(CronSchedule.java)

典型报错与异常栈 #

以下为实际场景中可能遇到的报错形态:

{
  "error": {
    "root_cause": [
      {
        "type": "parse_exception",
        "reason": "invalid time hour value [24] (possible values may be between 0 and 23 incl.)"
      }
    ],
    "type": "parse_exception",
    "reason": "invalid time hour value [24] (possible values may be between 0 and 23 incl.)"
  },
  "status": 400
}

2. 为什么会发生这个错误 #

Elasticsearch 的 Watcher 调度模块在解析 hour 字段时,会先读取数值,再调用 DayTimes.validHour(hour) 进行范围校验。只要数值不在 [0, 23] 闭区间内,就会立即抛出 ElasticsearchParseException

常见原因通常包括:

  • 使用了 24 小时制边界值错误:如将午夜写成 24 而不是 024:00 不是合法的 24 小时制表示。
  • cron 表达式配置错误:cron 的 hour 字段误写为 24-2324 等越界值。
  • 时区转换引入偏移:UTC 时间转换为本地时间时,偏移量计算错误导致 hour 落在范围外。
  • 动态计算 hour 值未做边界校验:通过脚本或模板动态生成 hour 值时,未对结果做 0-23 的截断或取模处理。
  • 数据来源污染:从外部系统读取的时间字符串包含非法值(如 99-1),解析后直接传入调度配置。
  • 版本差异:不同 Elasticsearch 版本对时间表达式的解析严格程度不同,升级后原本"宽松"的配置可能失效。

3. 如何排查和解决这个异常 #

建议按"先定位报错来源,再修正配置,后验证生效"的顺序处理:

  1. 定位报错中的具体 hour 值:从异常信息中提取方括号中的数值(如 [24]),确认越界的具体数字。
  2. 检查 Watcher 的 trigger 配置:调用 GET _watcher/watch/<watch_id> 查看对应 watch 的 trigger.schedule 部分,重点检查 hour 字段。
  3. 检查 cron 表达式:如果使用 cron 类型的 schedule,确认 cron 表达式中 hour 字段的值是否合法。
  4. 排查 hour 值的来源:如果 hour 值来自动态模板、脚本计算或外部数据源,追溯生成逻辑。
  5. 确认时区设置:检查 trigger.schedule 中是否配置了 tz(时区),时区偏移是否导致 hour 越界。
  6. 在测试环境复现:修复后先在测试环境注册同名 watch,确认不再报错再应用到生产环境。

排查时需要注意的问题 #

  • 不要只看异常信息的字面含义,必须结合 Watcher 的完整配置(triggerconditionactions)一起分析。
  • 如果 hour 值来自脚本字段或动态计算,需要同时检查脚本逻辑和输入数据的边界情况。
  • 涉及时区转换的场景,建议统一使用 UTC 时间并在展示层做转换,避免调度层出现偏移问题。
  • 批量更新 Watcher 时,建议逐个验证,避免将同一个错误配置扩散到多个 watch。

4. 如何解决这个错误 #

常用修复思路 #

  • 将 hour 值修正到 0-23 范围内24 改为 0-1 改为 23,或根据业务逻辑做正确的偏移计算。
  • 不要将 24:00 直接拆成 hour=2424:00 在 Elasticsearch 时间解析中应表示为第二天的 00:00,hour 字段应写 0 并调整日期。
  • 对 cron 表达式做合法性校验:cron 的 hour 字段合法值为 0-23,多个值用逗号分隔,范围用连字符,注意不要写成 24-23 这种反向区间。
  • 在动态生成 hour 值的代码中增加边界检查:使用取模运算确保结果落在合法范围内,例如 hour = ((rawHour % 24) + 24) % 24
  • 统一时区处理策略:明确 Watcher 使用的时区,避免 UTC 与本地时间混用导致的偏移错误。

修复示例 #

错误配置示例(hour = 24):

{
  "trigger": {
    "schedule": {
      "daily": {
        "at": {
          "hour": [24],
          "minute": [0]
        }
      }
    }
  }
}

修复后配置示例(hour = 0):

{
  "trigger": {
    "schedule": {
      "daily": {
        "at": {
          "hour": [0],
          "minute": [0]
        }
      }
    }
  }
}

cron 表达式错误示例:

{
  "trigger": {
    "schedule": {
      "cron": {
        "expression": "0 24 * * *"
      }
    }
  }
}

修复后 cron 表达式(使用 0 表示午夜):

{
  "trigger": {
    "schedule": {
      "cron": {
        "expression": "0 0 * * *"
      }
    }
  }
}

带时区配置的修复示例:

{
  "trigger": {
    "schedule": {
      "cron": {
        "expression": "0 9 * * *",
        "tz": "Asia/Shanghai"
      }
    }
  }
}

后续注意事项与推荐建议 #

  • 在创建 Watcher 的代码中增加 hour 值的前置校验,拒绝 0-23 以外的值,Fail Fast 优于运行时报错。
  • 对动态生成调度配置的场景,建议编写单元测试覆盖边界值(-10232499 等)。
  • 建立 Watcher 配置的代码审查机制,重点关注 trigger.schedule 部分的 hour、minute、cron 表达式是否合法。
  • 定期调用 GET _watcher/stats 检查 watch 的执行状态,及时发现因配置错误导致的 failed 状态。

借助 INFINI 产品提升排障效率 #

  • INFINI Console 适合查看集群健康度、索引状态、Watcher 执行历史和错误趋势,帮助快速判断异常是配置问题还是系统性问题。
  • INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测、限流和流量治理,可以在 Watcher 触发动作(如 webhook、index 操作)时提供请求审计和异常重试能力。
  • 建议将 Watcher 的变更记录、执行日志和错误告警统一接入监控面板,缩短从"发现 watch 执行失败"到"定位配置错误"的时间。

5. 小结 #

invalid time hour value [n] (possible values may be between 0 and 23 incl.) 是一个配置层面的解析异常,本质原因是 hour 数值越界。处理这类异常时,最有效的路径是:从报错信息提取越界值 -> 定位对应 Watcher 的 trigger 配置 -> 修正 hour 值并验证时区和 cron 表达式 -> 在代码中增加边界校验防止复发。

只要把 Watcher 配置的校验规则、时区处理策略和监控手段固定下来,这类异常基本可以在开发阶段就被拦截,不会流入生产环境。

相关错误 #

附:日志上下文 #

下面保留当前页面中的源码片段,便于结合异常调用栈定位问题:

int hour = parser.intValue();
if (DayTimes.validHour(hour) == false) {
    throw new ElasticsearchParseException(
        "invalid time hour value [{}] (possible values may be between 0 and 23 incl.)",
        hour);
}

DayTimes.validHour() 的校验逻辑等价于:

public static boolean validHour(int hour) {
    return hour >= 0 && hour <= 23;
}