Skip to content

Commit 9e0cd2f

Browse files
Use status code 500 for errors if no shard failed (#88551)
If there is no shard failure we would like to use a generic Internal Server Error other than a Service Unavailable. Moreover, if the cause is known we use a status code that reflects the cause.
1 parent a7b591b commit 9e0cd2f

File tree

4 files changed

+117
-1
lines changed

4 files changed

+117
-1
lines changed

docs/changelog/88551.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 88551
2+
summary: "Fix: use status code 500 for aggregation reduce phase errors if no shard failed"
3+
area: Search
4+
type: bug
5+
issues:
6+
- 20004

server/src/main/java/org/elasticsearch/action/search/ReduceSearchPhaseException.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
package org.elasticsearch.action.search;
1010

11+
import org.elasticsearch.ExceptionsHelper;
1112
import org.elasticsearch.common.io.stream.StreamInput;
13+
import org.elasticsearch.rest.RestStatus;
1214

1315
import java.io.IOException;
1416

@@ -27,4 +29,13 @@ public ReduceSearchPhaseException(String phaseName, String msg, Throwable cause,
2729
public ReduceSearchPhaseException(StreamInput in) throws IOException {
2830
super(in);
2931
}
32+
33+
@Override
34+
public RestStatus status() {
35+
final ShardSearchFailure[] shardFailures = shardFailures();
36+
if (shardFailures.length == 0) {
37+
return getCause() == null ? RestStatus.INTERNAL_SERVER_ERROR : ExceptionsHelper.status(getCause());
38+
}
39+
return super.status();
40+
}
3041
}

server/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public RestStatus status() {
7575
RestStatus status = shardFailures[0].status();
7676
if (shardFailures.length > 1) {
7777
for (int i = 1; i < shardFailures.length; i++) {
78-
if (shardFailures[i].status().getStatus() >= 500) {
78+
if (shardFailures[i].status().getStatus() >= RestStatus.INTERNAL_SERVER_ERROR.getStatus()) {
7979
status = shardFailures[i].status();
8080
}
8181
}

server/src/test/java/org/elasticsearch/ElasticsearchExceptionTests.java

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.apache.lucene.util.Constants;
1212
import org.elasticsearch.action.NoShardAvailableActionException;
1313
import org.elasticsearch.action.RoutingMissingException;
14+
import org.elasticsearch.action.search.ReduceSearchPhaseException;
1415
import org.elasticsearch.action.search.SearchPhaseExecutionException;
1516
import org.elasticsearch.action.search.ShardSearchFailure;
1617
import org.elasticsearch.action.support.broadcast.BroadcastShardOperationFailedException;
@@ -202,6 +203,104 @@ public void testGuessRootCause() {
202203
}
203204
}
204205

206+
public void testReduceSearchPhaseExceptionWithNoShardFailuresAndNoCause() throws IOException {
207+
final ReduceSearchPhaseException ex = new ReduceSearchPhaseException(
208+
"search",
209+
"no shard failure",
210+
null,
211+
ShardSearchFailure.EMPTY_ARRAY
212+
);
213+
214+
XContentBuilder builder = XContentFactory.jsonBuilder();
215+
builder.startObject();
216+
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
217+
builder.endObject();
218+
String expected = """
219+
{
220+
"type": "reduce_search_phase_exception",
221+
"reason": "[reduce] no shard failure",
222+
"phase": "search",
223+
"grouped": true,
224+
"failed_shards": []
225+
}""";
226+
assertEquals(XContentHelper.stripWhitespace(expected), Strings.toString(builder));
227+
assertEquals(RestStatus.INTERNAL_SERVER_ERROR.getStatus(), ex.status().getStatus());
228+
}
229+
230+
public void testReduceSearchPhaseExceptionWithNoShardFailuresAndCause() throws IOException {
231+
final ReduceSearchPhaseException ex = new ReduceSearchPhaseException(
232+
"search",
233+
"no shard failure",
234+
new IllegalArgumentException("illegal argument"),
235+
ShardSearchFailure.EMPTY_ARRAY
236+
);
237+
238+
XContentBuilder builder = XContentFactory.jsonBuilder();
239+
builder.startObject();
240+
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
241+
builder.endObject();
242+
String expected = """
243+
{
244+
"type": "reduce_search_phase_exception",
245+
"reason": "[reduce] no shard failure",
246+
"phase": "search",
247+
"grouped": true,
248+
"failed_shards": [],
249+
"caused_by":{"type":"illegal_argument_exception","reason":"illegal argument"}
250+
}""";
251+
assertEquals(XContentHelper.stripWhitespace(expected), Strings.toString(builder));
252+
assertEquals(RestStatus.BAD_REQUEST.getStatus(), ex.status().getStatus());
253+
}
254+
255+
public void testSearchPhaseExecutionExceptionWithNoShardFailuresAndNoCause() throws IOException {
256+
final SearchPhaseExecutionException ex = new SearchPhaseExecutionException(
257+
"search",
258+
"no shard failure",
259+
null,
260+
ShardSearchFailure.EMPTY_ARRAY
261+
);
262+
263+
XContentBuilder builder = XContentFactory.jsonBuilder();
264+
builder.startObject();
265+
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
266+
builder.endObject();
267+
String expected = """
268+
{
269+
"type": "search_phase_execution_exception",
270+
"reason": "no shard failure",
271+
"phase": "search",
272+
"grouped": true,
273+
"failed_shards": []
274+
}""";
275+
assertEquals(XContentHelper.stripWhitespace(expected), Strings.toString(builder));
276+
assertEquals(RestStatus.SERVICE_UNAVAILABLE.getStatus(), ex.status().getStatus());
277+
}
278+
279+
public void testReduceSearchPhaseExecutionExceptionWithNoShardFailuresAndCause() throws IOException {
280+
final SearchPhaseExecutionException ex = new SearchPhaseExecutionException(
281+
"search",
282+
"no shard failure",
283+
new IllegalArgumentException("illegal argument"),
284+
ShardSearchFailure.EMPTY_ARRAY
285+
);
286+
287+
XContentBuilder builder = XContentFactory.jsonBuilder();
288+
builder.startObject();
289+
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
290+
builder.endObject();
291+
String expected = """
292+
{
293+
"type": "search_phase_execution_exception",
294+
"reason": "no shard failure",
295+
"phase": "search",
296+
"grouped": true,
297+
"failed_shards": [],
298+
"caused_by":{"type":"illegal_argument_exception","reason":"illegal argument"}
299+
}""";
300+
assertEquals(XContentHelper.stripWhitespace(expected), Strings.toString(builder));
301+
assertEquals(RestStatus.BAD_REQUEST.getStatus(), ex.status().getStatus());
302+
}
303+
205304
public void testDeduplicate() throws IOException {
206305
{
207306
ShardSearchFailure failure = new ShardSearchFailure(

0 commit comments

Comments
 (0)