@@ -97,8 +97,8 @@ public static ElasticsearchException validate(
9797 String originalExpression = localResolvedIndices .original ();
9898 logger .debug ("Checking replaced expression for original expression [{}]" , originalExpression );
9999
100- // Check if this is a qualified resource (project:index pattern) or has project routing
101- boolean isQualifiedExpression = hasProjectRouting || RemoteClusterAware .isRemoteIndexName (originalExpression );
100+ // Check if this is a qualified resource (project:index pattern)
101+ boolean isQualifiedExpression = RemoteClusterAware .isRemoteIndexName (originalExpression );
102102
103103 Set <String > remoteExpressions = localResolvedIndices .remoteExpressions ();
104104 ResolvedIndexExpression .LocalExpressions localExpressions = localResolvedIndices .localExpressions ();
@@ -129,11 +129,16 @@ public static ElasticsearchException validate(
129129 originalExpression ,
130130 indicesOptions
131131 );
132- if (localException == null ) {
132+ if (localException == null && localExpressions != ResolvedIndexExpression . LocalExpressions . NONE ) {
133133 // found locally, continue to next expression
134134 continue ;
135135 }
136- boolean isUnauthorized = localException instanceof ElasticsearchSecurityException ;
136+ ElasticsearchSecurityException unauthorizedException = null ;
137+ if (localException instanceof ElasticsearchSecurityException securityException ) {
138+ unauthorizedException = securityException ;
139+ }
140+ assert localExpressions != ResolvedIndexExpression .LocalExpressions .NONE || false == remoteExpressions .isEmpty ()
141+ : "both local expression and remote expressions are empty which should have errored earlier at index rewriting time" ;
137142 boolean foundFlat = false ;
138143 // checking if flat expression matched remotely
139144 for (String remoteExpression : remoteExpressions ) {
@@ -150,17 +155,26 @@ public static ElasticsearchException validate(
150155 foundFlat = true ;
151156 break ;
152157 }
153- if (false == isUnauthorized && exception instanceof ElasticsearchSecurityException ) {
154- isUnauthorized = true ;
158+ if (unauthorizedException == null && exception instanceof ElasticsearchSecurityException securityException ) {
159+ unauthorizedException = securityException ;
155160 }
156161 }
157162 if (foundFlat ) {
158163 continue ;
159164 }
160- if (isUnauthorized ) {
165+ // Prefer reporting 403 over 404
166+ if (unauthorizedException != null ) {
167+ return unauthorizedException ;
168+ }
169+ // Prefer reporting 404 on origin over linked projects
170+ if (localException != null ) {
171+ assert localException instanceof IndexNotFoundException
172+ : "Expected local exception to be IndexNotFoundException, but found: " + localException ;
161173 return localException ;
174+ } else {
175+ assert false == remoteExpressions .isEmpty () : "expected remote expressions to be non-empty" ;
176+ return new IndexNotFoundException (remoteExpressions .iterator ().next ());
162177 }
163- return new IndexNotFoundException (originalExpression );
164178 }
165179 }
166180 // if we didn't throw before it means that we can proceed with the request
0 commit comments