{"id":253,"library":"grpcio-status","title":"grpcio-status","description":"grpcio-status provides the Python binding for the google.rpc.Status protobuf, enabling rich (structured) error details to be packed into gRPC trailing metadata and unpacked on the client side. It sits on top of grpcio and protobuf, exposing two primary helpers — rpc_status.to_status() and rpc_status.from_call() — both marked EXPERIMENTAL in the source. The package is versioned in strict lockstep with grpcio (current: 1.78.0) and is released on the same cadence, typically every 4–6 weeks.","status":"active","version":"1.78.0","language":"python","source_language":"en","source_url":"https://github.com/grpc/grpc/tree/master/src/python/grpcio_status","tags":["grpc","rpc","protobuf","status","error-handling","microservices","networking"],"install":[{"cmd":"pip install grpcio-status","lang":"bash","label":"pip (latest)"},{"cmd":"pip install \"grpcio-status==1.78.0\" \"grpcio==1.78.0\" \"googleapis-common-protos>=1.5.5\"","lang":"bash","label":"pin all three required packages together"}],"dependencies":[{"reason":"Core gRPC runtime — must match grpcio-status version exactly to avoid subtle ABI mismatches.","package":"grpcio","optional":false},{"reason":"Required for google.rpc.status_pb2 and Any packing/unpacking of error details. grpcio-status>=1.51 requires protobuf>=4.21.6.","package":"protobuf","optional":false},{"reason":"Provides google.rpc.code_pb2 and google.rpc.error_details_pb2 (RetryInfo, BadRequest, DebugInfo, etc.) used in rich error detail payloads.","package":"googleapis-common-protos","optional":true}],"imports":[{"note":"The installable package is grpcio-status but the importable top-level package is grpc_status (underscore, not hyphen). Direct module import without 'from' raises ImportError.","wrong":"import grpc_status.rpc_status","symbol":"rpc_status","correct":"from grpc_status import rpc_status"},{"note":"Pass the grpc.RpcError exception object directly — it implements grpc.Call. Returns None if the server did not pack a google.rpc.Status into trailing metadata; always guard against None.","symbol":"rpc_status.from_call","correct":"from grpc_status import rpc_status; status = rpc_status.from_call(rpc_error)"},{"note":"Use abort_with_status(rpc_status.to_status(...)) on the server side to send rich status atomically. Using set_code/set_details separately does NOT embed the google.rpc.Status proto in trailing metadata, so clients will receive None from from_call().","wrong":"context.set_code(...); context.set_details(...)","symbol":"rpc_status.to_status","correct":"from grpc_status import rpc_status; context.abort_with_status(rpc_status.to_status(rich_status))"},{"note":"google.rpc is supplied by googleapis-common-protos, not by grpcio-status itself. Install googleapis-common-protos separately.","symbol":"status_pb2.Status","correct":"from google.rpc import status_pb2"},{"note":"Structured detail types (BadRequest, RetryInfo, QuotaFailure, DebugInfo, etc.) live in googleapis-common-protos, not in grpcio-status.","symbol":"error_details_pb2","correct":"from google.rpc import error_details_pb2"}],"quickstart":{"code":"# pip install grpcio grpcio-status googleapis-common-protos\nimport grpc\nfrom grpc_status import rpc_status\nfrom google.rpc import status_pb2, code_pb2, error_details_pb2\nfrom google.protobuf import any_pb2\n\n# --- SERVER SIDE (inside a servicer method) ---\ndef MyRpc(request, context):\n    # Build a structured error detail\n    detail = any_pb2.Any()\n    detail.Pack(\n        error_details_pb2.BadRequest(\n            field_violations=[\n                error_details_pb2.BadRequest.FieldViolation(\n                    field=\"name\",\n                    description=\"must not be empty\",\n                )\n            ]\n        )\n    )\n    rich_status = status_pb2.Status(\n        code=code_pb2.INVALID_ARGUMENT,\n        message=\"Invalid request\",\n        details=[detail],\n    )\n    # abort_with_status atomically sets code + message + trailing metadata\n    context.abort_with_status(rpc_status.to_status(rich_status))\n\n# --- CLIENT SIDE ---\ndef call_rpc(stub):\n    try:\n        stub.MyRpc(request=object())  # placeholder\n    except grpc.RpcError as rpc_error:\n        # from_call returns None when no rich status was packed\n        status = rpc_status.from_call(rpc_error)\n        if status is None:\n            print(\"No rich status; plain code:\", rpc_error.code())\n            return\n        print(\"gRPC status code:\", rpc_error.code())\n        for detail in status.details:\n            if detail.Is(error_details_pb2.BadRequest.DESCRIPTOR):\n                info = error_details_pb2.BadRequest()\n                detail.Unpack(info)\n                for v in info.field_violations:\n                    print(f\"Field '{v.field}': {v.description}\")\n","lang":"python","description":"Server aborts with a rich google.rpc.Status; client unpacks the structured error detail."},"warnings":[{"fix":"Upgrade all protobuf-dependent packages to support protobuf>=4. If a transitive dep cannot be upgraded, pin grpcio-status to a pre-1.51 release (not recommended for production).","message":"grpcio-status>=1.51 requires protobuf>=4.21.6 and is incompatible with any dependency that pins protobuf<4.0.0. Mixing versions causes an unresolvable dependency conflict at install time.","severity":"breaking","affected_versions":">=1.51.0"},{"fix":"Always pin both packages to identical versions: pip install 'grpcio==1.78.0' 'grpcio-status==1.78.0'.","message":"grpcio and grpcio-status must share the exact same version. Installing mismatched versions (e.g. grpcio==1.77.0 with grpcio-status==1.78.0) causes runtime AttributeError or silent misbehaviour.","severity":"breaking","affected_versions":"all"},{"fix":"Always null-check the return value of from_call(). On the server, always use context.abort_with_status(rpc_status.to_status(rich_status)) to embed the google.rpc.Status in trailing metadata.","message":"rpc_status.from_call() returns None — not an empty Status — when the server used set_code()/set_details() instead of abort_with_status(rpc_status.to_status(...)). A failed RPC does not automatically generate a rich status proto.","severity":"gotcha","affected_versions":"all"},{"fix":"Use abort_with_status(rpc_status.to_status(rich_status)) exclusively — it atomically sets code, message, and trailing metadata so they stay consistent.","message":"from_call() raises ValueError if the gRPC call's status code or message text is inconsistent with the values inside the embedded google.rpc.Status proto. This happens when server code sets status code/message separately after packing the proto.","severity":"gotcha","affected_versions":"all"},{"fix":"Track the grpc/grpc GitHub releases page for changes to src/python/grpcio_status/grpc_status/rpc_status.py before upgrading.","message":"Both rpc_status.from_call() and rpc_status.to_status() are explicitly marked EXPERIMENTAL in the gRPC source and documentation; their signatures could change without a major version bump.","severity":"gotcha","affected_versions":"all"},{"fix":"Use: from grpc_status import rpc_status","message":"The importable package name is grpc_status (underscore) but the PyPI slug is grpcio-status (hyphen). Confusing them produces a ModuleNotFoundError even when the package is correctly installed.","severity":"gotcha","affected_versions":"all"},{"fix":"Allow typing-extensions>=4.13 in your dependency constraints: pip install 'typing-extensions>=4.13'.","message":"grpcio 1.78.0 introduces a new dependency on typing-extensions~=4.13. If your environment pins typing-extensions to an older version the install will fail.","severity":"deprecated","affected_versions":">=1.78.0"}],"env_vars":null,"last_verified":"2026-05-12T12:23:08.554Z","next_check":"2026-06-25T00:00:00.000Z","problems":[{"fix":"Ensure the `grpcio-status` package is installed using pip: `pip install grpcio-status`. If using virtual environments or tools like PySpark, verify that the package is installed in the correct environment being used by the application.","cause":"This error occurs when the Python interpreter cannot find the `grpc_status` module, typically because the `grpcio-status` package has not been installed or is not accessible in the current Python environment.","error":"ModuleNotFoundError: No module named 'grpc_status'"},{"fix":"Try to resolve the dependency conflict by either downgrading or upgrading your `protobuf` installation to a version compatible with `grpcio-status` and other dependent packages. A common strategy is to uninstall `protobuf` and `grpcio-status`, then reinstall `grpcio-status` which should pull a compatible `protobuf` version, or explicitly install a `protobuf` version known to work with your `grpcio-status` version.","cause":"This conflict arises because `grpcio-status` has specific version requirements for the `protobuf` library, and another installed package (or a different version of `protobuf` itself) has conflicting requirements, leading to an incompatible `protobuf` version in the environment.","error":"ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts. grpcio-status X.Y.Z requires protobuf<A.B.C,>=D.E.F, but you have protobuf G.H.I which is incompatible."},{"fix":"Access the status code by calling the `code()` method on the `RpcError` object: `error.code()` instead of `error.code`.","cause":"This error occurs when attempting to access the `code` attribute directly on a `grpc.RpcError` object as a property, rather than calling it as a method.","error":"AttributeError: 'RpcError' object has no attribute 'code'"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.26,"mem_mb":8,"disk_size":"41.1M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.27,"mem_mb":8.3,"disk_size":"41.5M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":7,"disk_size":"39M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":7.4,"disk_size":"39M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.69,"mem_mb":9,"disk_size":"43.7M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.69,"mem_mb":9.3,"disk_size":"44.0M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.23,"mem_mb":8.1,"disk_size":"42M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.27,"mem_mb":8.4,"disk_size":"42M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.86,"mem_mb":11.3,"disk_size":"35.4M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.82,"mem_mb":11.3,"disk_size":"35.8M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":10.4,"disk_size":"33M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":10.4,"disk_size":"34M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.81,"mem_mb":11.6,"disk_size":"35.1M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.79,"mem_mb":11.6,"disk_size":"35.4M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.45,"mem_mb":10.7,"disk_size":"33M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.46,"mem_mb":10.7,"disk_size":"33M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.2,"mem_mb":8,"disk_size":"40.6M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.2,"mem_mb":8.4,"disk_size":"40.9M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.17,"mem_mb":7.1,"disk_size":"39M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.18,"mem_mb":7.4,"disk_size":"39M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}