gRPC status codeの一覧

HTTPのステータスコードにあたる概念がgRPC Codeであり、以下で定義されている。
https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto

例えばGo言語だと以下にprotoから生成されたコードがある。
https://github.com/grpc/grpc-go/blob/master/codes/codes.go


## 一覧

適当に翻訳していく。

### `OK = 0`
* エラーなし。成功を返した。
* HTTPだと `200 OK`


### `CANCELLED = 1`
* 処理がキャンセルされた。通常は呼び出し側によるキャンセル。
* HTTPだと `499 Client Closed Request`

※`L`を2つ重ねるスペルなことに注意。後述


### `UNKNOWN = 2`
* 不明エラー。他のアドレス空間から受け取ったステータスを、適切にマッピングできなかったときに返される。
* 十分なエラー情報が得られなかったとき、このエラーに変換される可能性がある。
* HTTPだと `500 Internal Server Error`


### `INVALID_ARGUMENT = 3`
* クライアントが無効な引数を指定した。
* `FAILED_PRECONDITION`とは異なる。 `INVALID_ARGUMENT` は、システムの状態にかかわらず問題となる引数（例えば、不正なファイル名）を示す。
* HTTPだと `400 Bad Request`

### `DEADLINE_EXCEEDED = 4`
* 操作が完了する前にタイムアウトした。 
* システムの状態を変更する操作の場合、操作が正常に完了した場合でもこのエラーが返されることがある。たとえば、サーバーからの成功した応答が、期限が切れるのに十分なだけ長く遅延した可能性がある。
* HTTPだと `504 Gateway Timeout`

### `NOT_FOUND = 5`
* 要求されたエンティティ（ファイルやディレクトリなど）が見つからなかった。
* 開発者への注意
    * 段階的ロールアウトや秘密のホワイトリストなど、特定のユーザー区分全体に対する要求が拒否された場合は、 `NOT_FOUND`を使うことができる。
    * ユーザごとのアクセス制御など、一部のユーザに対して要求が拒否された場合、 `PERMISSION_DENIED` を使用するべき。
* HTTPだと `404 Not Found`

### `ALREADY_EXISTS = 6`
* クライアントが作成しようとしたエンティティ（ファイルやディレクトリなど）が既に存在する。
* HTTPだと `409 Conflict`

### `PERMISSION_DENIED = 7`
* 呼び出し元に、操作を実行する権限がない。
* `PERMISSION_DENIED`はリソースを使い果たしたことによる拒否のために使ってはならない
    * その場合、代わりに`RESOURCE_EXHAUSTED`を使用する
* 呼び出し側を識別できない場合は、`PERMISSION_DENIED`を使用するべきではない
    * その場合、代わりに`UNAUTHENTICATED`を使用する。
* このエラーコードは、要求が有効であること、または要求されたエンティティが存在すること、または他の前提条件を満たすことを意味しない
* HTTPだと `403 Forbidden`

### `UNAUTHENTICATED = 16`
* リクエストに適切な認証情報がない
* HTTPだと `401 Unauthorized`

### `RESOURCE_EXHAUSTED = 8`
* 一部のリソースが使い果たされている
* ユーザーごとの割り当て量不足
* またはファイルシステム全体のスペース不足
* HTTPだと `429 Too Many Requests`

### `FAILED_PRECONDITION = 9`
* システムが操作の実行に必要な状態ではないため、拒否された。 
    * たとえば、削除するディレクトリが空でない場合、rmdir操作がディレクトリ以外に適用される場合など。
* HTTPだと `400 Bad Request`
* `FAILED_PRECONDITION`, `ABORTED`, `UNAVAILABLE` の使い分け
    * クライアントが失敗した呼び出しだけを再試行できる場合は `UNAVAILABLE`
    * クライアントがより高いレベルで再試行する必要がある場合（たとえば、クライアントが指定したテストおよび設定が失敗した場合、クライアントがread-modify-writeシーケンスを再開する必要があることを示す）は、`ABORTED` 
    * システム状態が明示的に修正されるまでクライアントが再試行してはいけない場合は `FAILED_PRECONDITION`を使用する。例えば、ディレクトリが空でないために "rmdir"が失敗した場合、ファイルがディレクトリから削除されない限りクライアントは再試行してはいけないので `FAILED_PRECONDITION`

### `ABORTED = 10`
* 操作が中止された。通常、シーケンサチェックの失敗やトランザクションの中止などの同時実行性の問題が原因。
* `FAILED_PRECONDITION`, ` ABORTED`, `UNAVAILABLE`の使い分けは前述のガイドラインを参照。
* HTTPだと `409 Conflict`

### `OUT_OF_RANGE = 11`
* 操作が有効範囲を超えて実行された。 たとえば、過去のファイルの終わりを探したり読んだりした。
* `INVALID_ARGUMENT`とは異なり、このエラーはシステム状態が変化した場合に修正されるかもしれない。たとえば、32ビットファイルシステムは、[0,2 ^ 32-1]の範囲にないオフセットで読み込むように要求された場合には `INVALID_ARGUMENT`を生成するべき
* 単に、現在のファイルサイズを超えたオフセットから読み込むように要求された場合、それは `OUT_OF_RANGE`を生成するべき
* `FAILED_PRECONDITION`と` OUT_OF_RANGE`の間にはかなりの重複がある。
* 可能ならば`OUT_OF_RANGE`（より具体的なエラー）を使用することを推奨。ファイルシステムを探索する場合、呼び出し元は`OUT_OF_RANGE`を検査すれば終わったかどうか簡単に検出できるようになる。
* HTTPだと `400 Bad Request`

### `UNIMPLEMENTED = 12`
* その操作は実装されていないか、サポートされていない。
* HTTPなら `501 Not Implemented`

### `INTERNAL = 13`
* 内部エラー
* 基盤となるシステムが期待するいくつかの不変条件が破られたことを意味する。 
* このエラーコードは重大なエラーのために予約されている。
* HTTPなら `500 Internal Server Error`

### `UNAVAILABLE = 14`
* サービスが現在利用できない。 おそらく一時的な状態で、バックオフで再試行することで修正できる。
* `FAILED_PRECONDITION`, `ABORTED`, `UNAVAILABLE`の使い分けは前述
* HTTPなら `503 Service Unavailable`

### `DATA_LOSS = 15`

* 修復不能なデータ欠損や破損が起きた
* HTTPなら `500 Internal Server Error`


## gRPC→HTTP 対応表
一応抜き出して表にまとめてみる。概念が1対1ではないことがわかる。単純には比較できないことに注意されたし。

* HTTPはサーバー側のみでステータスを吐くのに対して、gRPCではクライアント側でもエラーを吐くことがある(CANCELLEDとか特に)

| gRPC | HTTP |
|:-:|:-:|
| OK = 0 | 200 OK |
| CANCELLED = 1 | 499 Client Closed Request |
| UNKNOWN = 2 | 500 Internal Server Error |
| INVALID_ARGUMENT = 3 | 400 Bad Request |
| DEADLINE_EXCEEDED = 4 | 504 Gateway Timeout  |
| NOT_FOUND = 5  | 404 Not Found  |
| ALREADY_EXISTS = 6  | 409 Conflict  |
| PERMISSION_DENIED = 7  |  403 Forbidden |
| UNAUTHENTICATED = 16 | 401 Unauthorized  |
| RESOURCE_EXHAUSTED = 8 | 429 Too Many Requests  |
| FAILED_PRECONDITION = 9  | 400 Bad Request  |
| ABORTED = 10  | 409 Conflict  |
| OUT_OF_RANGE = 11  | 400 Bad Request  |
| UNIMPLEMENTED = 12 | 501 Not Implemented  |
| INTERNAL = 13  | 500 Internal Server Error  |
| UNAVAILABLE = 14  | 503 Service Unavailable  |
| DATA_LOSS = 15  | 500 Internal Server Error |

## gRPC Gatewayでの gRPC→HTTP 対応表

実はprotoと完全一致ではなく、若干アレンジが加わっているようだ。

* `CANCELLED = 1` → `408 Request Timeout`
* `FAILED_PRECONDITION = 9` → `412 Precondition Failed`

* https://github.com/grpc-ecosystem/grpc-gateway/blob/main/runtime/errors.go

## cance*ll*ed? cance*l*ed?

`CANCELLED` はアメリカ英語つづりではないけど、protoに書かれてるのでこれでいいらしい。
Go版ではわざわざコード中の定数が `Canceled` アメリカ英語つづりになるように修正されてた。

## 参考

* [gRPCのstatusとerrdetails Go言語版コピペ用 - Qiita](https://qiita.com/Hiraku/items/89899bfc67abfed1fe6c)