{"id":37989729,"url":"https://github.com/tobbstr/grpcerr","last_synced_at":"2026-01-16T18:42:02.307Z","repository":{"id":48516026,"uuid":"377281495","full_name":"tobbstr/grpcerr","owner":"tobbstr","description":"A library which makes working with gRPC errors easy, both for gRPC and HTTP APIs.","archived":false,"fork":false,"pushed_at":"2021-07-21T21:08:28.000Z","size":50,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-17T04:43:00.678Z","etag":null,"topics":["errors","go","golang","grpc","http"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tobbstr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-15T20:07:33.000Z","updated_at":"2024-06-28T12:47:38.000Z","dependencies_parsed_at":"2022-09-14T16:40:16.040Z","dependency_job_id":null,"html_url":"https://github.com/tobbstr/grpcerr","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tobbstr/grpcerr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobbstr%2Fgrpcerr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobbstr%2Fgrpcerr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobbstr%2Fgrpcerr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobbstr%2Fgrpcerr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tobbstr","download_url":"https://codeload.github.com/tobbstr/grpcerr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobbstr%2Fgrpcerr/sbom","scorecard":{"id":890726,"data":{"date":"2025-08-11","repo":{"name":"github.com/tobbstr/grpcerr","commit":"e18493ff3bce0c03c738eaa495cb8140863faa9f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.8,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/6 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 13 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2023-2153 / GHSA-m425-mq94-257g / GHSA-qppj-fm5r-hxr3","Warn: Project is vulnerable to: GO-2024-2611 / GHSA-8r3f-844c-mc37"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T11:43:41.468Z","repository_id":48516026,"created_at":"2025-08-24T11:43:41.468Z","updated_at":"2025-08-24T11:43:41.468Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28481141,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["errors","go","golang","grpc","http"],"created_at":"2026-01-16T18:42:02.199Z","updated_at":"2026-01-16T18:42:02.287Z","avatar_url":"https://github.com/tobbstr.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TL;DR\n\nThis library enables API developers to use the gRPC error model for both gRPC and HTTP.\nIt provides an easy to use API for instantiating gRPC errors such as Unavailable, Resource Exhausted, Invalid argument etc,\nin addition to easily adding metadata such as a request ID, stack traces and more. It also facilitates encoding and writing of\ngRPC errors to an http.ResponseWriter. As of now, it only supports JSON-encoding.\n\n# Getting Started\n\nSo you want to get started using this library? Follow the instructions in this section.\n\n## Installation\n\nGiven the project that wants to use this library is using Go Modules, installing it is as easy as entering the following command:\n\n```\ngo get github.com/tobbstr/grpcerr\n```\n\nThis'll add it to the list of dependencies in the go.mod file.\n\n# Usage\n\n## Instantiation of a gRPC error\n\n```go\nimport (\n    \"github.com/tobbstr/grpcerr\"\n\t\"google.golang.org/genproto/googleapis/rpc/errdetails\"\n)\n\nfunc main() {\n    // Error details\n    errInfo := \u0026grpcerr.ErrorInfo{\n        Reason: \"Token expired\",\n        Domain: \"Authorization\",\n        Metadata: map[string]string{\n            \"TokenExpired\": \"2006-01-02 15:04:05\",\n        },\n    }\n\n    // Instantiation of the gRPC error\n    permissionDenied, err := grpcerr.NewPermissionDenied(\"\", errInfo)\n    if err != nil {\n        // handle error\n    }\n}\n```\n\n## Returning gRPC error from an HTTP API\n\n```go\nimport (\n    \"net/http\"\n    \"github.com/tobbstr/grpcerr\"\n\t\"google.golang.org/genproto/googleapis/rpc/errdetails\"\n)\n\n// controller definition omitted\n\nfunc (c *controller) awesomeEndpoint(w http.ResponseWriter, r *http.Request) {\n    // ... Do bunch of stuff ...\n\n    err = vitalFunc(...)\n    // Handles errors returned from an invocation.\n    // Note! err must be a gRPC error instantiated using this library\n    if err != nil {\n        encodeAndWrite := grpcerr.NewHttpResponseEncodeWriter(w)\n        if err = encodeAndWrite(err).AsJSON(); err != nil {\n            // Log and handle error. The error should normally be nil.\n        }\n        return\n    }\n\n    // Continue normal processing...\n}\n```\n\nThis is an example of a HTTP Response Body for an InvalidArgument gRPC error:\n\n```json\n{\n    \"code\":3,\n    \"message\":\"dummy-msg\",\n    \"details\":[\n        {\n            \"@type\":\"type.googleapis.com/google.rpc.BadRequest\",\n            \"fieldViolations\":[\n                {\n                    \"field\":\"dummy-field-violation-field\",\n                    \"description\":\"dummy-field-violation-desc\"\n                }\n            ]\n        }\n    ]\n}\n```\n\nIn terms of HTTP headers the HTTP status code is translated from the gRPC error code, but is overridable using\noptions when calling `grpcerr.NewHttpRresponseEncodeWriter(w, opts...)`. The below is an example of this:\n\n```go\n// defining the override\nwithStatusOK := func(w http.ResponseWriter) {\n    w.WriteHeader(http.StatusOK)\n}\n\n// use the option like this\nencodeAndWrite := NewHttpResponseEncodeWriter(w, withStatusOK)\n```\n\n## Wrapping of errors are supported\n\n```go\n// Somewhere in a service far, far away...\nfunc (svc *service) OrchestrateImportantAction() error {\n    // Something goes awry\n    if err != nil {\n        violations := []grpcerr.PreconditionFailure{\n            {\n                Type: \"Account missing\",\n                Subject: \"john.doe@example.com\",\n                Description: \"Callers must supply account information in request\",\n            },\n        }\n\n        failedPrecondition, err := grpcerr.NewFailedPrecondition(\"\", violations)\n        if err != nil {\n            // handle error\n        }\n\n        // Note! The returned error is a wrapped one, having the gRPC error as its root error. It does not matter how many times the gRPC error gets wrapped, as long as it's the root error.\n        return fmt.Errorf(\"could not perform something cool: %w\", failedPrecondition)\n    }\n}\n\n// Meanwhile in an HTTP controller not that far away\nfunc (c *controller) performImportantAction(w http.ResponseWriter, r *http.Request) {\n    // invoke svc, which returns a wrapped gRPC error instantiated using this library\n    err := c.svc.OrchestrateImportantAction()\n    if err != nil {\n        // ... Log the error ...\n\n        // write an HTTP response from the root error which is the gRPC error\n        encodeAndWrite := grpcerr.NewHttpResponseEncodeWriter(w)\n        if err = encodeAndWrite(err).AsJSON(); err != nil {\n            // handle error\n        }\n        return\n    }\n}\n```\n\n## Using gRPC errors in gRPC APIs\n\n```go\nfunc (c *gRPCController) AwesomeEndpoint(ctx context.Context, req *AwesomeRequest) (*AwesomeResponse, error) {\n    err := c.svc.OrchestrateImportantAction()\n    if err != nil {\n        // ... Log the error ...\n\n        // no additional processing required, return the error as is\n        return nil, err\n    }\n}\n```\n\n## Using gRPC errors in gRPC clients\n\n```go\nresponse, err := client.AwesomeEndpoint(...)\nif err != nil {\n    // gets the gRPC code\n    code := grpcerr.Code(err)\n\n    // gets the gRPC message\n    message := grpcerr.Message(err)\n\n    // gets the RequestInfo from the gRPC error\n    requestInfo := grpcerr.RequestInfoFrom(err)\n\n    // gets the DebugInfo from the gRPC error\n    debugInfo := grpcerr.DebugInfoFrom(err)\n\n    // gets the HelpLinks from the gRPC error\n    helpLinks := grpcerr.HelpLinksFrom(err)\n\n    // gets the LocalizedMessage from the gRPC error\n    localizedMessage := grpcerr.LocalizedMessageFrom(err)\n\n    // gets the QuotaViolations from the gRPC error\n    quotaViolations := grpcerr.QuotaViolationsFrom(err)\n\n    // gets the FieldViolations from the gRPC error\n    fieldViolations := grpcerr.FieldViolationsFrom(err)\n\n    // etc ...\n}\n```\n\n# Roadmap\n\nSee the [open issues](https://github.com/tobbstr/grpcerr/issues) for a list of proposed features (and known issues).\n\n# Contributing\n\nContributing can be done in more than one way. One way is to hit the star button. Another is to add to or improve the existing repo content. The following steps guide you how to do that. In any case, contributions are greatly appreciated.\n\n1. Clone this repo by entering this command in a terminal\n    ```sh\n    git clone https://github.com/tobbstr/grpcerr.git\n    ```\n2. Navigate to the repo folder\n3. Create a feature branch\n    ```sh\n    git checkout -b feature-name\n    ```\n4. Make the changes you want and commit them\n5. Push the branch to GitHub\n    ```sh\n    git push origin feature-name\n    ```\n6. Open a pull request\n\n# License\n\nDistributed under the [MIT](LICENSE) license.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobbstr%2Fgrpcerr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftobbstr%2Fgrpcerr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobbstr%2Fgrpcerr/lists"}