{"record":{"id":"93e193bf769f220f","repo":"micro/go-micro","slug":"go-micro-client","errorCode":"go.micro.client","errorMessage":"go.micro.client","messagePattern":"go\\.micro\\.client","errorType":"exception","errorClass":"errors.Error","httpStatus":null,"severity":"error","filePath":"client/grpc/error.go","lineNumber":39,"sourceCode":"\n\t// grpc error\n\ts, ok := status.FromError(err)\n\tif !ok {\n\t\treturn err\n\t}\n\n\t// return first error from details\n\tif details := s.Details(); len(details) > 0 {\n\t\treturn microError(details[0].(error))\n\t}\n\n\t// try to decode micro *errors.Error\n\tif e := errors.Parse(s.Message()); e.Code > 0 {\n\t\treturn e // actually a micro error\n\t}\n\n\t// fallback\n\treturn errors.New(\"go.micro.client\", s.Message(), microStatusFromGrpcCode(s.Code()))\n}\n\nfunc microStatusFromGrpcCode(code codes.Code) int32 {\n\tswitch code {\n\tcase codes.OK:\n\t\treturn http.StatusOK\n\tcase codes.InvalidArgument:\n\t\treturn http.StatusBadRequest\n\tcase codes.DeadlineExceeded:\n\t\treturn http.StatusRequestTimeout\n\tcase codes.NotFound:\n\t\treturn http.StatusNotFound\n\tcase codes.AlreadyExists:\n\t\treturn http.StatusConflict\n\tcase codes.PermissionDenied:\n\t\treturn http.StatusForbidden\n\tcase codes.Unauthenticated:\n\t\treturn http.StatusUnauthorized","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/client/grpc/error.go#L21-L57","documentation":"In client/grpc/error.go, microError converts a gRPC status error into a micro errors.Error. It first attempts to parse the message as an existing micro error; if that fails (code <= 0), it fabricates a new error with code \"go.micro.client\" and maps the gRPC status code to an HTTP-like status via microStatusFromGrpcCode. The message \"go.micro.client\" here is the error's Code/Id field, indicating a generic client-side gRPC failure.","triggerScenarios":"Any gRPC call made through the micro grpc client that returns a status error whose message is not a parseable micro error — e.g. transport failures, Unavailable, DeadlineExceeded, or server errors not formatted as micro errors.","commonSituations":"Calling a non-micro gRPC server through the micro client; server crashing or rejecting the RPC; network partitions; deadline exceeded on slow backends.","solutions":["Inspect the wrapped gRPC status (status.FromError) to see the real codes.Code and message","Use errors.Parse-style handling: check err.Code and err.Id to classify the failure","Add retry logic for transient codes (Unavailable, DeadlineExceeded) with backoff","Ensure server responses use micro error formatting so codes round-trip correctly"],"exampleFix":"// before\nerr := client.Call(ctx, req, rsp)\nif err != nil { return err }\n// after\nerr := client.Call(ctx, req, rsp)\nif err != nil {\n    if e, ok := err.(*errors.Error); ok && e.Code == 504 {\n        return retryWithBackoff(ctx, req, rsp)\n    }\n    return err\n}","handlingStrategy":"type-guard","validationCode":"if st, ok := status.FromError(err); ok && st.Code() == codes.Unavailable {\n    // safe to retry\n}","typeGuard":"func isMicroClientError(err error) (*errors.Error, bool) {\n    e, ok := err.(*errors.Error)\n    if !ok || e.Code == 0 { return nil, false }\n    return e, true\n}","tryCatchPattern":"err := client.Call(ctx, req, rsp)\nif e, ok := err.(*errors.Error); ok {\n    switch e.Code {\n    case 504: return retry(ctx, req, rsp)\n    case 503: return retryWithBackoff(ctx, req, rsp)\n    default: return err\n    }\n}\nreturn err","preventionTips":["Have servers return micro-formatted errors so codes round-trip","Classify gRPC status codes before deciding to retry","Add tracing to see the underlying gRPC status behind go.micro.client errors"],"tags":["grpc","micro","client","rpc"],"backgroundTag":"grpc-call-failed","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}