{
  "id": "grpc/client-certificate-required",
  "signature": "UNAVAILABLE: grpc: client certificate required for mutual TLS",
  "signature_zh": "UNAVAILABLE: grpc: 双向 TLS 需要客户端证书",
  "regex": "UNAVAILABLE: grpc: client certificate required for mutual TLS",
  "domain": "grpc",
  "category": "auth_error",
  "subcategory": null,
  "root_cause": "The gRPC server is configured for mutual TLS (mTLS) but the client did not provide a certificate, causing the TLS handshake to fail.",
  "root_cause_type": "generic",
  "root_cause_zh": "gRPC 服务器配置为双向 TLS (mTLS)，但客户端未提供证书，导致 TLS 握手失败。",
  "versions": [
    {
      "version": "gRPC Go 1.64.0",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    },
    {
      "version": "gRPC Python 1.63.0",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    },
    {
      "version": "gRPC Java 1.62.0",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    }
  ],
  "os_specific": {},
  "dead_ends": [
    {
      "action": "Disable TLS entirely by using insecure channel",
      "why_fails": "Server requires TLS; insecure connections are rejected at transport level.",
      "fail_rate": 0.9,
      "condition": "",
      "sources": []
    },
    {
      "action": "Use a self-signed server certificate on client but no client cert",
      "why_fails": "Client still does not provide required certificate; mTLS fails anyway.",
      "fail_rate": 0.8,
      "condition": "",
      "sources": []
    },
    {
      "action": "Set client certificate path to empty string hoping server skips validation",
      "why_fails": "gRPC requires a valid certificate file; empty path causes error or no certificate.",
      "fail_rate": 0.7,
      "condition": "",
      "sources": []
    }
  ],
  "workarounds": [
    {
      "action": "Configure client with a valid client certificate and key: `creds = grpc.ssl_channel_credentials(root_certificates=root_cert, private_key=client_key, certificate_chain=client_cert)` then use `grpc.secure_channel('host:port', creds)`",
      "success_rate": 0.95,
      "how": "Configure client with a valid client certificate and key: `creds = grpc.ssl_channel_credentials(root_certificates=root_cert, private_key=client_key, certificate_chain=client_cert)` then use `grpc.secure_channel('host:port', creds)`",
      "condition": "",
      "sources": []
    },
    {
      "action": "If testing, generate client cert using openssl: `openssl req -newkey rsa:2048 -nodes -keyout client.key -x509 -days 365 -out client.crt` and pass to credentials",
      "success_rate": 0.85,
      "how": "If testing, generate client cert using openssl: `openssl req -newkey rsa:2048 -nodes -keyout client.key -x509 -days 365 -out client.crt` and pass to credentials",
      "condition": "",
      "sources": []
    }
  ],
  "workarounds_zh": [
    "使用有效客户端证书和密钥配置客户端：`creds = grpc.ssl_channel_credentials(root_certificates=root_cert, private_key=client_key, certificate_chain=client_cert)` 然后使用 `grpc.secure_channel('host:port', creds)`",
    "测试时，使用 openssl 生成客户端证书：`openssl req -newkey rsa:2048 -nodes -keyout client.key -x509 -days 365 -out client.crt` 并传给凭据"
  ],
  "transition_graph": {
    "leads_to": [],
    "preceded_by": [],
    "frequently_confused_with": []
  },
  "official_doc_url": "https://grpc.io/docs/guides/auth/#with-client-side-ssl",
  "official_doc_section": null,
  "error_code": null,
  "verification_tier": "ai_generated",
  "confidence": 0.86,
  "fix_success_rate": 0.9,
  "resolvable": "true",
  "first_seen": "2024-02-05",
  "last_confirmed": "2024-06-01",
  "last_updated": "2024-06-01",
  "evidence_count": 1,
  "tags": [],
  "locale": "en",
  "aliases": []
}