适用版本: 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. 排查步骤 #
- 打印最终发给 Elasticsearch 的原始 HTTP 请求体,不要只看上层对象。
- 确认请求体首字符是否为
{,而不是[、"或其他内容。 - 如果请求由 SDK、模板或脚本构造,检查是否发生了二次 JSON 编码。
- 对照接口文档确认该 API 是否要求整个 body 为对象。
- 在测试环境用最小合法对象重试,确认问题是否只在请求根结构。
4. 修复建议 #
- 把请求体改成标准 JSON 对象,而不是数组或字符串。
- 对模板输出增加断言,确保空分支也返回合法对象。
- 避免手工拼接 JSON,优先使用结构化序列化。
- 在网关或调用层记录原始请求体,方便快速识别根节点类型错误。
5. 小结 #
这个异常并不复杂,核心就是 整个搜索请求体的根节点类型错了。一旦确认最终发出的 body 不是对象,修复路径通常就非常直接。
相关错误 #
- could-not-parse-inner-source-definition:无法解析 inner _source 定义
- failed-to-parse-object-expected-start-object-but-was:对象解析失败
- failed-to-parse-request:请求解析失败
附:日志上下文 #
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);
}





