You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A malformed search term typed by a user makes GET /api/v1/search/query return 500. Nothing on the server failed — OpenSearch correctly rejected an unparseable query — so this is a client input error reported as a server fault. It should be 400.
Reproducible from the UI with no special setup: type a AND OR b into any search box that reaches /search/query (found via the domain selector, see #31822). escapeESReservedCharacters on the UI side escapes reserved characters, not boolean keywords, so AND OR arrives at OpenSearch as an operator sequence.
{"code":500,"message":"Search failed due to [es/search] failed: [search_phase_execution_exception] all shards failed | Root cause: [query_shard_exception: Failed to parse query [*a AND OR b*]]"}
Measured status codes
Against a local 1.13 stack, every /search/query failure mode returns 500 — the endpoint appears unable to return 400:
Request
Status
Cause
q=*a AND OR b*
500
query_shard_exception: Failed to parse query — client input
q=*a~~b*, q=*a^^b*
500
same, unparseable operators — client input
q=* with from=9995
500
illegal_argument_exception: Result window is too large — client input
index=nope_search_index
500
Failed to find index — client input
For contrast, sibling endpoints classify correctly — /api/v1/domains/hierarchy?fields=parent,bogus returns 400 Invalid field name bogus.
Why this matters beyond the status code
Alerting noise. Every malformed search increments the 5xx rate. Anything paging on server-error rate or an availability SLO fires on what is a user typo.
It hides real outages. A genuine cluster problem and a user typing AND OR are indistinguishable in metrics and logs.
Clients can't classify. A UI cannot tell "your query is malformed, fix it" from "the search backend is down, retry later", so it can't offer the right recovery. This came up directly in review on Fixes #31822: Surface domain tree search failures instead of rejecting unhandled #31823: a reviewer asked to show the server's message only for 4xx and stay generic for 5xx, which is reasonable — except the one message a user can act on is currently a 500.
Shared surface./search/query backs Explore, the global search bar, and every entity picker, so this is not specific to one dropdown.
Expected behavior
An OpenSearch/Elasticsearch rejection caused by the request itself — query parse failures, an out-of-range result window, an unknown index — returns 400 with a message the client can show. Reserve 500 for genuine backend failures: cluster unreachable, timeouts, node failures.
Where the mapping lives
SearchException already supports a status — the single-argument constructor is what pins everything to 500:
openmetadata-service/src/main/java/org/openmetadata/service/search/elasticsearch/ElasticSearchSearchManager.java — the mirrored builder, ~line 1409
Both already unwrap error().rootCause() to build the message, so the root-cause type() needed for the decision is in hand. Suggested classification by root-cause type: query_shard_exception / parsing_exception / illegal_argument_exception / index_not_found_exception → 400; everything else → 500. Whatever the final list, it must be applied to both managers — they are kept in sync.
Suggested follow-up (separate, UI side)
Escaping or rejecting boolean keywords in escapeESReservedCharacters would stop the most common malformed query from ever leaving the browser. That is defence in depth, not the fix — any API client can still send one.
Version
OpenMetadata: 1.13 / main
Found while fixing #31822 (UI: a failed domain search was silently rendered as an empty result). That PR handles the client side; this issue is the server-side classification.
Affected module
Backend / Search
Describe the bug
A malformed search term typed by a user makes
GET /api/v1/search/queryreturn 500. Nothing on the server failed — OpenSearch correctly rejected an unparseable query — so this is a client input error reported as a server fault. It should be 400.Reproducible from the UI with no special setup: type
a AND OR binto any search box that reaches/search/query(found via the domain selector, see #31822).escapeESReservedCharacterson the UI side escapes reserved characters, not boolean keywords, soAND ORarrives at OpenSearch as an operator sequence.{"code":500,"message":"Search failed due to [es/search] failed: [search_phase_execution_exception] all shards failed | Root cause: [query_shard_exception: Failed to parse query [*a AND OR b*]]"}Measured status codes
Against a local 1.13 stack, every
/search/queryfailure mode returns 500 — the endpoint appears unable to return 400:q=*a AND OR b*query_shard_exception: Failed to parse query— client inputq=*a~~b*,q=*a^^b*q=*withfrom=9995illegal_argument_exception: Result window is too large— client inputindex=nope_search_indexFailed to find index— client inputFor contrast, sibling endpoints classify correctly —
/api/v1/domains/hierarchy?fields=parent,bogusreturns400 Invalid field name bogus.Why this matters beyond the status code
AND ORare indistinguishable in metrics and logs./search/querybacks Explore, the global search bar, and every entity picker, so this is not specific to one dropdown.Expected behavior
An OpenSearch/Elasticsearch rejection caused by the request itself — query parse failures, an out-of-range result window, an unknown index — returns 400 with a message the client can show. Reserve 500 for genuine backend failures: cluster unreachable, timeouts, node failures.
Where the mapping lives
SearchExceptionalready supports a status — the single-argument constructor is what pins everything to 500:Both search managers funnel every OpenSearch/ES error through one builder, so the classification has a single natural home in each:
openmetadata-service/src/main/java/org/openmetadata/service/search/opensearch/OpenSearchSearchManager.java—buildSearchException(OpenSearchException), ~line 1588openmetadata-service/src/main/java/org/openmetadata/service/search/elasticsearch/ElasticSearchSearchManager.java— the mirrored builder, ~line 1409Both already unwrap
error().rootCause()to build the message, so the root-causetype()needed for the decision is in hand. Suggested classification by root-cause type:query_shard_exception/parsing_exception/illegal_argument_exception/index_not_found_exception→ 400; everything else → 500. Whatever the final list, it must be applied to both managers — they are kept in sync.Suggested follow-up (separate, UI side)
Escaping or rejecting boolean keywords in
escapeESReservedCharacterswould stop the most common malformed query from ever leaving the browser. That is defence in depth, not the fix — any API client can still send one.Version
mainFound while fixing #31822 (UI: a failed domain search was silently rendered as an empty result). That PR handles the client side; this issue is the server-side classification.