luci: Index | Files

package appstatus

import ""

Package appstatus can attach/reterieve an application-specific response status to/from an error. It designed to prevent accidental exposure of internal statuses to RPC clients, for example Spanner's statuses.

Attaching a status

Use ToError, Error and Errorf to create new status-annotated errors. Use Attach and Attachf to annotate existing errors with a status.

if req.PageSize < 0  {
   return appstatus.Errorf(codes.InvalidArgument, "page size cannot be negative")
if err := checkState(); err != nil {
  return appstatus.Attachf(err, codes.PreconditionFailed, "invalid state")

This may be done deep in the function call hierarchy.

Do not use appstatus in code where you don't explicitly intend to return a specific status. This is unnecessary because any unrecognized error is treated as internal and because it is explicitly prohibited to attach a status to an error chain multiple times. When a status is attached, the package supports its propagation all the way to the requester unless there is code that explicitly throws it away.

Returning a status

Use GRPCifyAndLog right before returning the error from a gRPC method handler. Usually it is done in a Postlude of a service decorator, see ../cmd/svcdec.

func NewMyServer() pb.MyServer {
  return &pb.DecoratedMyServer{
    Service:  &actualImpl{},
    Postlude: func(ctx context.Context, methodName string, rsp proto.Message, err error) error {
      return appstatus.GRPCifyAndLog(ctx, err)

It recognizes only appstatus-annotated errors and treats any other error as internal. This behavior is important to avoid accidentally returning errors from Spanner or other client library that also uses grpc/status package to communicate status code from *other* services. For example, if a there is a typo in Spanner SQL statement, spanner package may return a status-annotated errors with code NotFound. In this case, our RPC must respond with internal error and not NotFound.


Package Files

doc.go helpers.go status.go

func Attach Uses

func Attach(err error, status *status.Status) error

Attach attaches an application-specific status to the error. The status will be shared with the RPC client as is. If err already has an application-specific status attached, panics.

func Attachf Uses

func Attachf(err error, code codes.Code, format string, args ...interface{}) error

Attachf is a shortcut for Attach(err, status.Newf(...))

func BadRequest Uses

func BadRequest(err error, details ...*errdetails.BadRequest) error

BadRequest annotates err as a bad request. The error message is shared with the requester as is.

func Error Uses

func Error(code codes.Code, msg string) error

Error returns an error with an application-specific status. The message will be shared with the RPC client as is.

func Errorf Uses

func Errorf(code codes.Code, format string, args ...interface{}) error

Errorf returns an error with an application-specific status. The message will be shared with the RPC client as is.

func GRPCifyAndLog Uses

func GRPCifyAndLog(ctx context.Context, err error) error

GRPCifyAndLog returns a GRPC error. If the error doesn't have a GRPC status attached by this package, internal error is assumed. Any internal or unknown errors are logged.

func Get Uses

func Get(err error) (st *status.Status, ok bool)

Get returns an application-specific Status attached to err using this package. If not explicitly set or if err is nil, then ok is false.

func MustWithDetails Uses

func MustWithDetails(s *status.Status, details ...proto.Message) *status.Status

MustWithDetails adds details to a status and asserts it is successful.

func ToError Uses

func ToError(s *status.Status) error

ToError converts an application-specific status to an error.

Package appstatus imports 6 packages (graph) and is imported by 27 packages. Updated 2020-11-16. Refresh now. Tools for package owners.