适用版本: 6.8-8.9
1. 错误说明 #
unknown month 是 Elasticsearch 在解析日期、时间表达式或 Watcher 调度配置时抛出的 ElasticsearchParseException。当输入的月份值无法被识别为合法的月份名称或数字时,Elasticsearch 会抛出此异常并中断当前操作。
该错误最常见于以下场景:
- Watcher 定时任务配置:在
trigger.schedule.monthly或cron表达式中使用了非法月份值。 - 日期字段解析:索引中文档的日期字段格式与 mapping 中定义的
format不匹配,导致_bulk写入或更新时解析失败。 - 脚本与聚合:在 Painless 脚本或
date_histogram聚合中使用了动态构造的日期字符串,其中包含非法月份。 - 快照恢复调度:在配置快照生命周期管理(SLM)或定时快照时,调度表达式中的月份部分有误。
典型报错 #
ElasticsearchParseException: unknown month [13]
ElasticsearchParseException: unknown month [Foo]
在更复杂的场景中,还可能伴随以下异常栈:
org.elasticsearch.ElasticsearchParseException: unknown month [13]
at org.elasticsearch.common.joda.JodaDateParser.parseMonth(JodaDateParser.java:xxx)
at org.elasticsearch.xpack.watcher.trigger.schedule.CronScheduleFactory.parse(CronScheduleFactory.java:xxx)
at org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTrigger.parseSchedule(ScheduleTrigger.java:xxx)
2. 原因分析 #
从 Elasticsearch 源码中可以看到,月份解析逻辑位于日期解析器中,当输入值无法匹配任何已知月份时抛出 ElasticsearchParseException。常见根因如下:
2.1 月份数字超出合法范围 #
月份的有效范围是 1-12(对应 January 到 December)。以下情况会触发异常:
- 使用了
0或负数,如on: [0]。 - 使用了大于
12的数字,如on: [13]、on: [99]。 - 使用了浮点数或科学记数法,如
on: [1.5]、on: [1e1]。
2.2 月份名称拼写错误 #
Elasticsearch 仅识别英文月份名称(不区分大小写),且支持以下形式:
| 月份 | 合法值 |
|---|---|
| 1月 | jan, january |
| 2月 | feb, february |
| 3月 | mar, march |
| 4月 | apr, april |
| 5月 | may |
| 6月 | jun, june |
| 7月 | jul, july |
| 8月 | aug, august |
| 9月 | sep, september |
| 10月 | oct, october |
| 11月 | nov, november |
| 12月 | dec, december, last |
以下拼写会被拒绝:Janurary(多了一个 u)、Decemeber(少了一个 c)、Sept(少了 em)。
2.3 本地化月份名称不被支持 #
Elasticsearch 的日期解析器默认基于英文月份名称,不支持中文、日文、西班牙文等本地化月份名称。例如:
一月、二月等中文月份名称会触发unknown month。enero、febrero等西班牙文月份名称同样不被识别。
2.4 日期格式配置错误 #
当索引 mapping 中日期字段的 format 与写入数据不匹配时,也会间接触发此异常。例如:
- mapping 定义
format: "yyyy-MM-dd",但写入了2024-13-01(月份为 13)。 - 使用
strict_前缀格式(如strict_year_month)时,任何非法值都会直接抛异常而非被忽略。
2.5 Watcher cron 表达式错误 #
在 Watcher 的 cron 表达式中,月份字段的有效值为 1-12 或 JAN-DEC(大写)。常见错误包括:
- 使用了
0作为月份值(cron 月份从 1 开始)。 - 使用了三位缩写但拼写错误,如
JUNN。 - 混淆了 cron 月份(1-12)与
Calendar月份(0-11)的索引差异。
3. 解决方案 #
方案一:修正 Watcher 调度配置中的月份值 #
错误示例 — 月份值超出范围:
{
"trigger": {
"schedule": {
"monthly": {
"on": [13]
}
}
}
}
正确示例:
{
"trigger": {
"schedule": {
"monthly": {
"on": [1, 6, 12]
}
}
}
}
方案二:使用合法的月份名称 #
在支持月份名称的配置项中,使用英文全称或标准三字母缩写:
{
"trigger": {
"schedule": {
"cron": "0 0 1 JAN,APR,JUL,OCT * ?"
}
}
}
如果需要使用"最后一个月"的语义,可以使用 last 关键字(仅特定 API 支持):
{
"trigger": {
"schedule": {
"monthly": {
"on": ["last"]
}
}
}
}
方案三:修正日期字段 mapping 与写入数据 #
检查索引 mapping 中日期字段的格式定义:
GET /your_index/_mapping
确保写入的日期字符串符合 mapping 中声明的格式:
# 假设 mapping 中 format 为 "yyyy-MM-dd"
# 正确写入
POST /your_index/_doc
{
"event_date": "2024-06-15"
}
# 错误写入(月份 13 不存在)
POST /your_index/_doc
{
"event_date": "2024-13-15"
}
如需同时支持多种日期格式,可在 mapping 中使用逗号分隔多个格式:
{
"mappings": {
"properties": {
"event_date": {
"type": "date",
"format": "yyyy-MM-dd||yyyy/MM/dd||epoch_millis"
}
}
}
}
方案四:验证并修复 cron 表达式 #
使用以下命令验证 cron 表达式是否合法:
# 在 Elasticsearch 中测试 Watcher cron 表达式
POST /_watcher/_parse
{
"schedule": {
"cron": "0 0 1 * * ?"
}
}
4. 预防措施 #
- 配置校验:在提交 Watcher 或索引模板前,使用 Kibana 的 Dev Tools 或 INFINI Console 事先校验 JSON 合法性,重点检查日期和调度字段。
- 统一日期格式:在团队内部约定统一的日期字符串格式(推荐 ISO-8601:
yyyy-MM-dd'T'HH:mm:ssZ),并在 mapping 中明确声明。 - 使用 strict 格式:在 mapping 中使用
strict_前缀格式(如strict_date_optional_time),可以在写入阶段快速暴露非法日期值,避免脏数据进入索引。 - CI/CD 校验:将 Watcher 配置和索引模板纳入版本管理,在 CI 流水线中加入静态检查步骤,拦截非法月份值和日期格式。
- 监控与告警:通过 INFINI Console 监控集群中
ElasticsearchParseException的出现频率,及时发现由日期解析失败引起的写入异常。
5. 借助 INFINI 产品提升排障效率 #
- INFINI Console 可用于查看集群日志、检索
ElasticsearchParseException异常分布,并快速定位触发异常的索引和请求来源。 - INFINI Gateway 部署在 Elasticsearch 前端,可以对写入请求做日期字段预校验和异常请求拦截,在请求到达 Elasticsearch 之前发现并阻断非法日期数据。
6. 小结 #
unknown month 的本质是 Elasticsearch 日期解析器无法将输入值映射为合法月份。排查时应优先检查 Watcher 调度配置、cron 表达式以及日期字段的 mapping 与写入数据是否一致。大多数情况下,将月份值修正为 1-12 范围内的整数或使用标准英文月份名称即可解决。
相关错误 #
- unknown-day-of-week-how-to-solve-this-elasticsearch-exception
- unknown-month-number-how-to-solve-this-elasticsearch-exception
- parse-exception-how-to-solve-this-elasticsearch-exception
- illegal-argument-exception-how-to-solve-this-elasticsearch-exception
附:日志上下文 #
下面是 Elasticsearch 源码中月份解析的相关片段,便于结合异常调用栈定位问题:
case "8"; "aug"; "august" -> AUGUST;
case "9"; "sep"; "september" -> SEPTEMBER;
case "10"; "oct"; "october" -> OCTOBER;
case "11"; "nov"; "november" -> NOVEMBER;
case "12"; "dec"; "last"; "december" -> DECEMBER;
default -> throw new ElasticsearchParseException("unknown month [{}]", value);





