es-client: non-JSON error responses report "Body is unusable" instead of the HTTP status
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 75/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- nodejs, typescript
調査の方向性
バグは src/lib/es-client.ts の 125-132 行目にあります。まずファイルを読み、リクエストフローを理解してください。修正方法は、kibana-client.ts や cloud-client.ts が処理するのと同様に、レスポンスボディをまずテキストとして読み取り、その後 JSON として解析を試みることです。非 JSON のエラーレスポンスを返すモック HTTP サーバーを使用してエラーを再現するテストを作成し、修正が正しいステータスコードとボディを返すことを確認してください。
索引モデルが issue の本文から書いたものです。
説明
Summary
Any non-2xx response whose body is not valid JSON surfaces as Error: Body is unusable: Body has already been read, losing the status code. That is undici's TypeError — the error branch of
EsClient.request reads the body twice. Deterministic, not timing-dependent.
The usual way to hit it is a reverse proxy in front of Elasticsearch: proxy_read_timeout expiring
on a long ES|QL query returns an nginx HTML 504, and the CLI reports Body is unusable instead of
504 — pointing suspicion at the client rather than the proxy.
Root cause
src/lib/es-client.ts#L125-L132:
if (!response.ok) {
let body: unknown
try {
body = await response.json() // consumes the stream
} catch {
body = await response.text() // ← throws: body already consumed
}
throw new EsResponseError(response.status, body)
}
response.json() disturbs the body even when it rejects, so the catch branch can never read it.
Reproduction
cat > elasticrc-local.yml <<'YAML'
current_context: local
contexts:
local:
elasticsearch:
url: http://127.0.0.1:9999
auth: { api_key: ZmFrZTpmYWtl }
YAML
chmod 0600 elasticrc-local.yml
export ELASTIC_CLI_CONFIG_FILE="$PWD/elasticrc-local.yml" NO_PROXY=localhost,127.0.0.1
# stand in for "ES behind a proxy that timed out"
node -e 'require("http").createServer((q,s)=>{s.writeHead(504,{"content-type":"text/html"});s.end("<html><body>504 Gateway Time-out</body></html>")}).listen(9999,"127.0.0.1")' &
elastic es esql query --query 'FROM x | LIMIT 1' --format txt
# Error: Body is unusable: Body has already been read (exit 1)
Same for 502, 503, text/plain and empty bodies. A JSON error body works correctly
(Error: illegal_argument_exception: …). Reproduced on v0.4.0 and v0.5.0, Node v26.8.1,
Linux x86_64, against Elasticsearch 9.5.3.
Suggested fix
Read once, then parse — as kibana-client.ts#L212
and cloud-client.ts#L75
already do in this repo:
const text = await response.text()
let body: unknown
try {
body = JSON.parse(text)
} catch {
body = text
}
throw new EsResponseError(response.status, body)
EsResponseError's message should also carry the status, since a string body currently renders as
bare HTML. Happy to open a PR with tests for an HTML and an empty error body.
Context
Introduced by #281 (native-fetch EsClient); @elastic/transport handled it correctly. Present in
every release since v0.2.0 and on main today. #588 fixed the same blind-JSON.parse mistake on
the success branch of this file — this is the error branch.
- 主要言語
- TypeScript
- スター
- 43
- フォーク
- 24
- 平均マージ
- 1日 5時間
- マージ済み PR(30日)
- 61
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
elastic/cli のほかの issue
-
cloud enhancement
難易度 1/5 1〜3時間 初心者へのやさしさ 88/100
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
bcgov/bc-wallet-mobile#4761 · コメント 1 件 ·
-
external-issue to-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
-
area-deployment area-integrations triage:bot-seen
難易度 2/5 半日 初心者へのやさしさ 86/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
refactor
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100