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

适用版本: 6.8-7.15

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

failed to parse search source. source must be an object; but found [{}] instead 表示 Elasticsearch 已经开始读取请求体,但拿到的第一个 token 不是 START_OBJECT。换句话说,请求体本该是一个 JSON 对象,例如 { "query": ... },结果却传成了数组、字符串、数字,甚至空值。

从保留的源码看,这个异常出现在 Graph 请求解析阶段,但本质上属于 整个请求体根节点结构错误

常见现象 #

  • 请求立即返回 400,还没进入真正的查询执行阶段。
  • 报错里会直接指出 source must be an object
  • 常见于网关转发、SDK 封装、模板渲染或脚本拼接 JSON 时。

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

  • 传给 Elasticsearch 的 body 是数组 []、字符串或其他非对象类型。
  • 代码把已经序列化好的 JSON 字符串再次包了一层,导致最终结构错误。
  • 某些请求把 source 参数作为 URL 参数或文本片段传递,解析后不是合法对象。
  • 模板分支为空时输出了 []"",而不是 {}

3. 排查步骤 #

  1. 打印最终发给 Elasticsearch 的原始 HTTP 请求体,不要只看上层对象。
  2. 确认请求体首字符是否为 {,而不是 [" 或其他内容。
  3. 如果请求由 SDK、模板或脚本构造,检查是否发生了二次 JSON 编码。
  4. 对照接口文档确认该 API 是否要求整个 body 为对象。
  5. 在测试环境用最小合法对象重试,确认问题是否只在请求根结构。

4. 修复建议 #

  • 把请求体改成标准 JSON 对象,而不是数组或字符串。
  • 对模板输出增加断言,确保空分支也返回合法对象。
  • 避免手工拼接 JSON,优先使用结构化序列化。
  • 在网关或调用层记录原始请求体,方便快速识别根节点类型错误。

5. 小结 #

这个异常并不复杂,核心就是 整个搜索请求体的根节点类型错了。一旦确认最终发出的 body 不是对象,修复路径通常就非常直接。

相关错误 #

附:日志上下文 #

try (XContentParser parser = request.contentOrSourceParamParser()) {  XContentParser.Token token = parser.nextToken();  if (token != XContentParser.Token.START_OBJECT) {
 throw new ElasticsearchParseException("failed to parse search source. source must be an object; but found [{}] instead";
 token.name());
 }
 parseHop(parser; currentHop; graphRequest);
 }