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

适用版本: 6.8-8.11

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

Invalid date received; ... 表示 Elasticsearch 在将输入文本转换为日期字面量时失败,常见于 Elasticsearch SQL 或 EQL 查询解析路径中。当 SQL 语句或表达式中的日期字符串无法被解析为有效的 java.time.LocalDate 对象时,底层会抛出 DateTimeParseException,外层再包装成 ParsingException 并抛出当前异常。

常见现象 #

  • 执行 Elasticsearch SQL 查询时返回 400 Bad Request 错误。
  • 错误响应中通常包含 Invalid date received; 开头的错误信息,后面跟随具体的解析失败原因。
  • 在 Elasticsearch 服务日志中可以找到 ParsingExceptionDateTimeParseException 相关堆栈。
  • 使用 JDBC 客户端或通过 REST API 直接调用 SQL 接口时均可能触发该异常。

典型报错与异常栈 #

{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "Invalid date received; Text '2023-13-01' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 13"
      }
    ],
    "type": "parsing_exception",
    "reason": "Invalid date received; Text '2023-13-01' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 13"
  },
  "status": 400
}

底层 Java 异常栈通常类似:

ParsingException: Invalid date received; Text '2023-13-01' could not be parsed
Caused by: java.time.format.DateTimeParseException: Text '2023-13-01' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 13
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:...
    at org.elasticsearch.xpack.sql.parser.CaseInsensitiveLiteralsParser.asDateOnly(CaseInsensitiveLiteralsParser.java:...)

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

Invalid date received 异常的触发根因是日期文本不符合 yyyy-MM-dd 格式要求,或日期值本身非法。常见原因包括:

  • 日期格式不匹配:传入的日期字符串不符合 ISO 标准格式 yyyy-MM-dd,例如使用了 MM/dd/yyyydd-MM-yyyy 等非预期格式。
  • 日期值非法:日期中的年、月、日数值超出有效范围,例如第 13 个月、第 32 天、2 月 30 日等。
  • 混入时间或时区信息:在只接受纯日期(date only)的位置传入了 datetime 或带时区的时间字符串,例如 2023-01-01T00:00:00Z
  • 空字符串或 null 值:SQL 查询中引用了空值或空字符串作为日期字面量。
  • 字符编码或不可见字符:日期字符串前后包含空格、制表符、换行符或其他不可见字符,导致解析失败。
  • SQL 生成逻辑缺陷:应用层动态拼接 SQL 时,日期变量未正确格式化,或变量替换后产生了畸形日期字符串。

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

建议按以下步骤进行排查:

  1. 获取完整错误信息:从 Elasticsearch 响应或日志中提取完整的异常信息,重点关注 Text '...' 部分,确认具体是哪个日期字符串解析失败。

  2. 确认日期格式要求:Elasticsearch SQL 引擎在解析日期字面量时,默认期望 yyyy-MM-dd 格式。确认你的输入是否匹配该格式。

  3. 检查 SQL 语句:如果是直接执行 SQL,检查 SQL 文本中所有的日期字面量;如果是应用生成 SQL,打印最终发给 Elasticsearch 的 SQL 语句。

  4. 验证日期值合法性:确认年、月、日在有效范围内(年:合理范围;月:1-12;日:1-28/29/30/31,取决于月份和闰年)。

  5. 排查字符污染:检查日期字符串是否包含不可见字符,可以使用 SELECT HEX(date_column) 或在应用层打印字符串的字节表示。

排查命令示例 #

# 查看 Elasticsearch 日志中的日期解析错误
grep -r "Invalid date received" /var/log/elasticsearch/

# 使用 curl 直接测试 SQL 查询
curl -X POST "localhost:9200/_sql" -H "Content-Type: application/json" -d '{
  "query": "SELECT * FROM my_index WHERE date_field = 2023-01-01"
}'

# 检查索引中日期字段的实际数据格式
curl -X GET "localhost:9200/my_index/_search" -H "Content-Type: application/json" -d '{
  "size": 10,
  "_source": ["date_field"],
  "query": { "match_all": {} }
}'

4. 如何解决这个错误 #

常用修复思路 #

  • 统一日期格式:确保所有日期字面量使用 yyyy-MM-dd 格式。如果数据源使用其他格式,在传入 SQL 前进行转换。

  • 校验日期值合法性:在应用层对日期值做前置校验,确保月、日数值在有效范围内,避免 2 月 30 日等非法日期传入。

  • 分离日期与时间:如果实际需要的是 datetime,应使用 CAST 函数或明确指定 timestamp 类型,而不是将 datetime 字符串直接用作 date 字面量。

  • 清洗输入字符串:去除日期字符串前后的空格和不可见字符,防止解析失败。

  • 使用参数化查询:避免直接拼接 SQL 字符串,使用 Elasticsearch SQL 的参数化方式或预处理方式传入日期值。

修复示例 #

-- 错误示例:格式不正确
SELECT * FROM orders WHERE order_date = '01/01/2023';

-- 正确示例:使用标准格式
SELECT * FROM orders WHERE order_date = '2023-01-01';

-- 使用 CAST 处理 datetime 转 date
SELECT * FROM orders WHERE CAST(order_timestamp AS DATE) = '2023-01-01';
// Java 应用层日期格式化示例
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formattedDate = LocalDate.now().format(formatter);
// 使用 formattedDate 拼接 SQL 或作为参数传入

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

  • 在应用层建立日期格式化工具类,统一所有日期输出的格式,避免各处散落不同的日期格式处理逻辑。
  • 对用户输入的日期做严格的格式校验和范围校验,在到达 Elasticsearch 之前就拦截非法输入。
  • 如果业务需要支持多种日期格式,考虑在 Elasticsearch 端使用 DATE_PARSE 函数进行显式转换,而不是依赖隐式解析。

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

  • INFINI Console 可以查看 Elasticsearch 集群的 SQL 查询日志、错误趋势和慢查询记录,帮助快速定位哪些 SQL 语句产生了日期解析错误,以及这些语句的来源和频率。

  • INFINI Gateway 部署在 Elasticsearch 前面时,可以对 SQL 请求进行观测和审计,记录所有失败的 SQL 语句及其完整上下文,同时支持对日期格式进行正则校验和请求改写,在网关层拦截非法日期输入。

  • 对于需要支持多种日期格式的业务场景,INFINI Gateway 的脚本过滤功能可以在请求到达 Elasticsearch 之前对日期字符串进行标准化处理,减少因日期格式问题导致的查询失败。

5. 小结 #

Invalid date received 是一个典型的 SQL 字面量解析异常,根因几乎总是日期文本格式或值不符合 yyyy-MM-dd 的要求。处理该异常时,应先从错误信息中提取具体的失败日期字符串,确认其格式和值是否合法,然后在应用层统一日期格式化逻辑。结合 INFINI Console 的查询审计和 INFINI Gateway 的请求治理能力,可以从根源上减少此类异常的发生。

相关错误 #

参考文档 #

附:日志上下文 #

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

try {
    return new Literal(source, asDateOnly(string), SqlDataTypes.DATE);
} catch (DateTimeParseException ex) {
    throw new ParsingException(source, "Invalid date received; {}", ex.getMessage());
}