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

适用版本: 6.8-8.9

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

could not parse time [value] 是 Elasticsearch 在解析时间值或时间配置时抛出的异常。此错误表示时间值、时间单位、时区或日期字段格式不满足解析器要求。

该错误通常在解析请求体时就会返回 ElasticsearchParseException,常见于 dailyweeklymonthly 等 schedule 的 at 字段配置中,或涉及时间字段的查询和聚合中。

常见现象 #

  • 请求通常在解析阶段直接失败,常见异常类型是 ElasticsearchParseExceptionMapperParsingExceptionSettingsException
  • 返回结果多为 400,并且日志里会直接点名出错字段、时间值或期望的数据类型。
  • 如果这个请求来自 SDK、模板或自动化脚本,往往同一类请求会持续复现,直到参数结构被修正。

典型报错与异常栈 #

{
  "error": {
    "root_cause": [
      {
        "type": "parse_exception",
        "reason": "could not parse time [25:00]. time hour [25] is not a number between 0 and 23"
      }
    ],
    "type": "parse_exception",
    "reason": "could not parse time [25:00]. time hour [25] is not a number between 0 and 23"
  },
  "status": 400
}

服务端日志中可能出现类似以下内容:

[2024-01-15T10:30:00,123][WARN ][o.e.x.w.t.s.DayTimes   ] [node-1] failed to parse time
ElasticsearchParseException[could not parse time [25:00]. time hour [25] is not a number between 0 and 23]
    at org.elasticsearch.xpack.watcher.trigger.schedule.DayTimes.parse(DayTimes.java:145)
    at org.elasticsearch.xpack.watcher.trigger.schedule.DailySchedule.parse(DailySchedule.java:89)

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

could not parse time 错误的根本原因是时间值或时间配置不符合 Elasticsearch 解析器的要求。

常见原因包括:

  • 分钟、小时等数值超出合法范围:例如小时值 25(超出 0-23 范围)、分钟值 60(超出 0-59 范围)。
  • 时间间隔缺少单位:例如应写成 10s5m,却只传了裸数字 105
  • 使用了非法时区:例如 UTC+25Invalid/Timezone 等不合法的时区标识符。
  • 使用了非法日期值:例如 2024-13-01(月份 13 不存在)、2024-01-32(日期 32 不存在)。
  • Elasticsearch 不接受的小数时间间隔:例如 5.5m,因为 Long.parseLong() 无法解析小数。
  • 时间格式错误:例如 25:00(小时超出范围)、ab:cd(非数字)、12-30(错误分隔符)。
  • 模板渲染问题:使用 Mustache 或 script 模板时,渲染结果可能格式不正确或包含空值。

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

排查步骤 #

  1. 先对照下方日志上下文,确认报错点究竟是字段名、字段值类型、缺失参数,还是某个不受支持的组合

  2. 回看最终发送给 Elasticsearch 的请求或配置,重点检查具体的时间字段、单位、时区和值范围

# 获取 watch 配置(如果是 schedule 相关错误)
GET _watcher/watch/<watch_id>?pretty

# 检查 trigger 部分的 schedule
  1. 在测试环境保留最小可复现输入,逐步把字段加回去,定位到底是哪一个字段或哪一层对象触发了解析异常
# 最小可工作的 daily schedule
PUT _watcher/watch/<watch_id>
{
  "trigger": {
    "schedule": {
      "daily": {
        "at": ["12:00"]
      }
    }
  },
  "input": {
    "simple": {}
  },
  "actions": {
    "log": {
      "logging": {
        "text": "Test"
      }
    }
  }
}
  1. 对照当前 Elasticsearch 版本文档确认该字段、类型或组合是否仍然受支持,避免套用旧版本示例

排查时需要注意的问题 #

  • 注意时间格式必须是 HH:MM(24小时制),且小时在 0-23 范围内,分钟在 0-59 范围内。
  • 如果使用了模板变量,确保变量渲染后不会产生空值、小数或非法格式。
  • 检查是否有不可见字符(如制表符、换行符、零宽空格)混入时间字符串。

4. 如何解决这个错误 #

常用修复方式 #

  • 把分钟、小时等值改到合法范围内,并使用解析器接受的字符串或数字格式
# 修复前(错误:小时值超出范围)
PUT _watcher/watch/<watch_id>
{
  "trigger": {
    "schedule": {
      "daily": {
        "at": ["25:00"]  # 错误:小时 25 超出范围
      }
    }
  }
}

# 修复后(正确:小时在 0-23 范围内)
PUT _watcher/watch/<watch_id>
{
  "trigger": {
    "schedule": {
      "daily": {
        "at": ["23:00"]  # 正确
      }
    }
  }
}
  • 为持续时间补上明确单位,例如 mssmh
# 修复前(错误:缺少单位)
"interval": 5  # 错误

# 修复后(正确:补上单位)
"interval": "5m"  # 正确
  • 去掉小数时间间隔和非法时区,统一改成 Elasticsearch 支持的格式
# 修复前(错误:小数时间间隔)
"interval": "5.5m"  # 错误

# 修复后(正确:整数)
"interval": "5m"  # 正确

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

  • 在测试环境保留最小可复现输入,逐步把字段加回去,定位到底是哪一个字段或哪一层对象触发了解析异常。
  • 对动态生成的配置进行格式验证,确保时间值合法。
  • 建立配置检查清单,在提交前验证所有时间字段的合法性。

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

  • INFINI Console 提供可视化的 Watch 编辑和验证功能,可以在保存前检查时间配置的合法性,自动检测超出范围的值或格式错误。
  • INFINI Gateway 可以记录 Watcher API 和搜索 API 的完整请求内容,帮助捕获时间配置的详细错误上下文,并通过流量回放验证修复方案。
  • 通过 INFINI Console 的 Watch 测试功能,可以在不执行完整 Watch 的情况下验证时间配置的合法性。

5. 小结 #

could not parse time [value] 这类异常的根因通常不是运行时故障,而是请求结构、映射定义或配置契约不满足 Elasticsearch 的明确要求。修复时优先看报错里指出的字段和期望类型,先把输入改到合法形态,再继续排查后续问题。

通过 INFINI Console 的配置验证功能和 INFINI Gateway 的请求捕获能力,可以更高效地定位和修复时间解析问题。

相关错误 #

参考文档 #

附:日志上下文 #

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

    throw new ElasticsearchParseException("could not parse time [{}]. time minute [{}] is not a number", time, minStr);
}
try {
    return new DayTimes(time, hour, minute);
} catch (IllegalArgumentException iae) {
    throw new ElasticsearchParseException("could not parse time [{}]", iae);
}
}

public void validate() {
    for (int i = 0; i < hour.length; i++) {