Skip to content

ES|QL GET _query/async/{id} returns inconsistent headers #135042

@lukasolson

Description

@lukasolson

Elasticsearch Version

9.2.0-SNAPSHOT

Installed Plugins

No response

Java Version

bundled

OS Version

Darwin

Problem Description

When an ES|QL async query is submitted (POST _query/async), the headers in the response contain both a x-elasticsearch-async-id and x-elasticsearch-async-is-running:

{
  "x-elasticsearch-async-is-running": "?1",
  "x-elastic-product": "Elasticsearch",
  "transfer-encoding": "chunked",
  "x-opaque-id": "eb265ac8-a1ef-4d93-9e78-e5a50845d6df;kibana:application:discover:new;application:discover:new",
  "content-type": "application/vnd.elasticsearch+json;compatible-with=9",
  "took-nanos": "201111334",
  "x-elasticsearch-async-id": "FnRUYVdrbElOUUR1VUdCUm1xZ3hHVncdd2RJMUtWU01SQlNmQk1icFgtNGp4QTo1NzU5MTY="
}

If the query takes a bit of time, then we poll on the ID returned in the first request. While the query is still running, the response headers from polling (GET _query/async/{id}) do not contain the x-elasticsearch-async-id and x-elasticsearch-async-is-running headers:

{
  "x-elastic-product": "Elasticsearch",
  "transfer-encoding": "chunked",
  "x-opaque-id": "5f8c8392-b269-496d-8c3e-76508e388cab;kibana:application:discover:new;application:discover:new",
  "content-type": "application/json",
  "took-nanos": "204451667"
}

However, when the request completes, the response from polling (still GET _query/async/{id}) do contain these headers:

{
  "x-elasticsearch-async-is-running": "?0",
  "x-elastic-product": "Elasticsearch",
  "transfer-encoding": "chunked",
  "warning": "299 Elasticsearch-9.2.0-09250da4bdc785e783e9dbb221b489d665fa91b4 \"No limit defined, adding default limit of [1000]\"",
  "x-opaque-id": "0aefa8fb-0e42-4488-931d-da573eb8ecfe;kibana:application:discover:new;application:discover:new",
  "content-type": "application/json",
  "took-nanos": "17916093875",
  "x-elasticsearch-async-id": "FnRUYVdrbElOUUR1VUdCUm1xZ3hHVncdd2RJMUtWU01SQlNmQk1icFgtNGp4QTo1NzU5MTY="
}

These headers should be consistently returned from the endpoint regardless of the status of the underlying query. For context, the is-running header is important in Kibana to determine whether we should continue polling.

Steps to Reproduce

POST /_query/async?drop_null_columns
{"wait_for_completion_timeout":"200ms","keep_on_completion":true,"keep_alive":"60000ms","query":"FROM filebeat-* METADATA _index\n  | EVAL buckets = DATE_TRUNC(5 minute, @timestamp), delay = DELAY(10ms)\n  | STATS count = COUNT(*) BY buckets, delay","locale":"en","include_ccs_metadata":true,"filter":{"bool":{"must":[],"filter":[{"range":{"@timestamp":{"format":"strict_date_optional_time","gte":"2025-09-18T21:38:06.992Z","lte":"2025-09-18T21:53:06.992Z"}}}],"should":[],"must_not":[]}}}

// After a few seconds, poll every few seconds
GET /_query/async/{id}?wait_for_completion_timeout=200ms&keep_alive=60000ms&drop_null_columns=true

The latter query returns inconsistent headers.

Logs (if relevant)

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions