Skip to content

Commit 00b9040

Browse files
authored
fix(api_core): clarify misleading http 404 unimplemented error message (#17681)
### **Summary of the issue:** **Context:** When a gRPC call fails with grpc.StatusCode.UNIMPLEMENTED but the error details string includes "Received http2 header with status: 404", the google-api-core library currently translates this into google.api_core.exceptions.MethodNotImplemented. This scenario often happens due to client-side configuration errors like an incorrect api_endpoint or a malformed resource path, not because the method is actually unimplemented. **Actual Behavior:** The library raises google.api_core.exceptions.MethodNotImplemented: 501 Received http2 header with status: 404. This exception is misleading because the primary issue indicated by the underlying error is related to the 404 (Not Found), not that the method is unimplemented (501). This makes debugging difficult for users. **Expected Behavior:** google-api-core should raise an exception that better reflects the underlying HTTP 404. Suggested improvements: Prioritize the 404 status when present in the details, raising google.api_core.exceptions.NotFound (404). The goal is to provide a more actionable error message to the user, guiding them to check the endpoint or resource path. Fixes b/362438722
1 parent 7c18c24 commit 00b9040

2 files changed

Lines changed: 31 additions & 5 deletions

File tree

packages/google-api-core/google/api_core/exceptions.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@
1818
on :mod:`google.api_core`, including both HTTP and gRPC clients.
1919
"""
2020

21-
from __future__ import absolute_import
22-
from __future__ import unicode_literals
21+
from __future__ import absolute_import, unicode_literals
2322

2423
import http.client
25-
from typing import Optional, Dict
2624
import warnings
25+
from typing import Dict, Optional
2726

2827
from google.rpc import error_details_pb2
2928

@@ -657,9 +656,20 @@ def from_grpc_error(rpc_exc):
657656
grpc is not None and isinstance(rpc_exc, grpc.Call)
658657
) or _is_informative_grpc_error(rpc_exc):
659658
details, err_info = _parse_grpc_error_details(rpc_exc)
659+
message = rpc_exc.details()
660+
if (
661+
grpc is not None
662+
and rpc_exc.code() == grpc.StatusCode.UNIMPLEMENTED
663+
and "Received http2 header with status: 404" in message
664+
):
665+
message = (
666+
f"{message}. This usually indicates that the 'api_endpoint' "
667+
"configuration in ClientOptions is incorrect, contains a typo, "
668+
"or is an invalid regional endpoint for this service."
669+
)
660670
return from_grpc_status(
661671
rpc_exc.code(),
662-
rpc_exc.details(),
672+
message,
663673
errors=(rpc_exc,),
664674
details=details,
665675
response=rpc_exc,

packages/google-api-core/tests/unit/test_exceptions.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@
2525
except ImportError: # pragma: NO COVER
2626
grpc = rpc_status = None
2727

28-
from google.api_core import exceptions
2928
from google.protobuf import any_pb2, json_format
3029
from google.rpc import error_details_pb2, status_pb2
3130

31+
from google.api_core import exceptions
32+
3233

3334
def test_create_google_cloud_error():
3435
exception = exceptions.GoogleAPICallError("Testing")
@@ -393,3 +394,18 @@ def test_error_details_from_grpc_response_unknown_error():
393394
and exception.domain is None
394395
and exception.metadata is None
395396
)
397+
398+
399+
@pytest.mark.skipif(grpc is None, reason="No grpc")
400+
def test_from_grpc_error_misleading_404():
401+
message = "Received http2 header with status: 404"
402+
error = mock.create_autospec(grpc.Call, instance=True)
403+
error.code.return_value = grpc.StatusCode.UNIMPLEMENTED
404+
error.details.return_value = message
405+
406+
exception = exceptions.from_grpc_error(error)
407+
408+
assert isinstance(exception, exceptions.MethodNotImplemented)
409+
assert exception.grpc_status_code == grpc.StatusCode.UNIMPLEMENTED
410+
assert "Received http2 header with status: 404" in exception.message
411+
assert "api_endpoint" in exception.message

0 commit comments

Comments
 (0)