diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java index 712f1d874e663..47476a0a67f7a 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java @@ -202,9 +202,9 @@ public void testIndicesDontExist() throws IOException { indexTimestampData(docsTest1, "test1", "2024-11-26", "id1"); ResponseException e = expectThrows(ResponseException.class, () -> runEsql(timestampFilter("gte", "2020-01-01").query(from("foo")))); - assertEquals(400, e.getResponse().getStatusLine().getStatusCode()); - assertThat(e.getMessage(), containsString("verification_exception")); - assertThat(e.getMessage(), anyOf(containsString("Unknown index [foo]"), containsString("Unknown index [remote_cluster:foo]"))); + assertEquals(404, e.getResponse().getStatusLine().getStatusCode()); + assertThat(e.getMessage(), containsString("index_not_found_exception")); + assertThat(e.getMessage(), anyOf(containsString("no such index [foo]"), containsString("Unknown index [remote_cluster:foo]"))); e = expectThrows(ResponseException.class, () -> runEsql(timestampFilter("gte", "2020-01-01").query(from("foo*")))); assertEquals(400, e.getResponse().getStatusLine().getStatusCode()); diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryIT.java index b4a5c82f74b93..4716e5537538b 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryIT.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.esql.action; import org.elasticsearch.Build; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; @@ -155,14 +156,10 @@ public void testSearchesAgainstNonMatchingIndicesWithLocalOnly() throws Exceptio { String q = "FROM nomatch," + localIndex; - IndexNotFoundException e = expectThrows(IndexNotFoundException.class, () -> runQuery(q, false)); - assertThat(e.getDetailedMessage(), containsString("no such index [nomatch]")); - - // MP TODO: am I able to fix this from the field-caps call? Yes, if we detect concrete vs. wildcard expressions in user query - // TODO bug - this does not throw; uncomment this test once https://github.com/elastic/elasticsearch/issues/114495 is fixed - // String limit0 = q + " | LIMIT 0"; - // VerificationException ve = expectThrows(VerificationException.class, () -> runQuery(limit0, false)); - // assertThat(ve.getDetailedMessage(), containsString("No matching indices for [nomatch]")); + expectNotFoundExceptionForQuery(q, "no such index [nomatch]", false); + + String limit0 = q + " | LIMIT 0"; + expectNotFoundExceptionForQuery(limit0, "no such index [nomatch]", false); } { @@ -186,8 +183,8 @@ public void testSearchesAgainstNonMatchingIndicesWithLocalOnly() throws Exceptio } { String q = "FROM nomatch"; - String expectedError = "Unknown index [nomatch]"; - expectVerificationExceptionForQuery(q, expectedError, false); + String expectedError = "no such index [nomatch]"; + expectNotFoundExceptionForQuery(q, expectedError, false); } { String q = "FROM nomatch*"; @@ -273,8 +270,8 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception { // missing concrete local index is an error { String q = "FROM nomatch,cluster-a:" + remote1Index; - String expectedError = "Unknown index [nomatch]"; - expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta); + String expectedError = "no such index [nomatch]"; + expectNotFoundExceptionForQuery(q, expectedError, requestIncludeMeta); } // missing concrete remote index is fatal @@ -300,6 +297,13 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception { } } + // missing concrete remote index is fatal + { + String q = "FROM logs*,cluster-a:logs*,cluster-a:nomatch"; + String expectedError = "Unknown index [cluster-a:logs*,nomatch]"; + expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta); + } + // No error since local non-matching index has wildcard and the remote cluster index expression matches { String remote1IndexName = randomFrom(remote1Index, IDX_ALIAS, FILTERED_IDX_ALIAS); @@ -384,8 +388,8 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception { // an error is thrown if there is a concrete index that does not match { String q = "FROM cluster-a:nomatch"; - String expectedError = "Unknown index [cluster-a:nomatch]"; - expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta); + String expectedError = "no such index [nomatch]"; + expectExceptionForQuery(q, expectedError, requestIncludeMeta, IndexNotFoundException.class); } // an error is thrown if there are no matching indices at all - single remote cluster with wildcard index expression @@ -398,8 +402,8 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception { // an error is thrown if there is a concrete index that does not match { String q = "FROM nomatch*,cluster-a:nomatch"; - String expectedError = "Unknown index [cluster-a:nomatch,nomatch*]"; - expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta); + String expectedError = "no such index [nomatch]"; + expectNotFoundExceptionForQuery(q, expectedError, requestIncludeMeta); } // an error is thrown if there are no matching indices at all - local with wildcard, remote with wildcard @@ -410,13 +414,13 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception { } { String q = "FROM nomatch,cluster-a:nomatch"; - String expectedError = "Unknown index [cluster-a:nomatch,nomatch]"; - expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta); + String expectedError = "no such index [nomatch]"; + expectNotFoundExceptionForQuery(q, expectedError, requestIncludeMeta); } { String q = "FROM nomatch,cluster-a:nomatch*"; - String expectedError = "Unknown index [cluster-a:nomatch*,nomatch]"; - expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta); + String expectedError = "no such index [nomatch]"; + expectNotFoundExceptionForQuery(q, expectedError, requestIncludeMeta); } // --- test against 3 clusters @@ -465,11 +469,32 @@ record ExpectedCluster(String clusterAlias, String indexExpression, EsqlExecutio * extra processing step to ensure that ESQL coordinator-only operations throw the same VerificationError. */ private void expectVerificationExceptionForQuery(String query, String error, Boolean requestIncludeMeta) { - VerificationException e = expectThrows(VerificationException.class, () -> runQuery(query, requestIncludeMeta)); + expectExceptionForQuery(query, error, requestIncludeMeta, VerificationException.class); + } + + /** + * Runs the provided query, expecting a VerificationError. It then runs the same query with a "| LIMIT 0" + * extra processing step to ensure that ESQL coordinator-only operations throw the same VerificationError. + */ + private void expectNotFoundExceptionForQuery(String query, String error, Boolean requestIncludeMeta) { + expectExceptionForQuery(query, error, requestIncludeMeta, IndexNotFoundException.class); + } + + /** + * Runs the provided query, expecting a VerificationError. It then runs the same query with a "| LIMIT 0" + * extra processing step to ensure that ESQL coordinator-only operations throw the same VerificationError. + */ + private void expectExceptionForQuery( + String query, + String error, + Boolean requestIncludeMeta, + Class clazz + ) { + ET e = expectThrows(clazz, () -> runQuery(query, requestIncludeMeta)); assertThat(e.getDetailedMessage(), containsString(error)); String limit0 = query + " | LIMIT 0"; - e = expectThrows(VerificationException.class, () -> runQuery(limit0, requestIncludeMeta)); + e = expectThrows(clazz, () -> runQuery(limit0, requestIncludeMeta)); assertThat(e.getDetailedMessage(), containsString(error)); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java index 16401574b0f58..200af16c69758 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java @@ -54,7 +54,7 @@ public class IndexResolver { public static final String UNMAPPED = "unmapped"; public static final IndicesOptions FIELD_CAPS_INDICES_OPTIONS = IndicesOptions.builder() - .concreteTargetOptions(IndicesOptions.ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS) + .concreteTargetOptions(IndicesOptions.ConcreteTargetOptions.ERROR_WHEN_UNAVAILABLE_TARGETS) .wildcardOptions( IndicesOptions.WildcardOptions.builder() .matchOpen(true)