This is a proto file that defines the sphere errors framework with status codes and messages. It provides extensions for protobuf enums to support structured error handling in Go applications.
- Enum-level default status code configuration
- Per-value error customization (status, reason, message)
- Integration with HTTP status codes
- Support for custom error messages and reasons
- Designed for use with
protoc-gen-sphere-errorsplugin
The core proto file defines:
syntax = "proto3";
package sphere.errors;
import "google/protobuf/descriptor.proto";
message Error {
int32 status = 1; // HTTP status code
string reason = 2; // Optional reason string
string message = 3; // Human-readable error message
}
extend google.protobuf.EnumOptions {
int32 default_status = 18534200; // Default status for entire enum
}
extend google.protobuf.EnumValueOptions {
Error options = 18534210; // Per-value error configuration
}syntax = "proto3";
package api.v1;
import "sphere/errors/errors.proto";
enum UserError {
option (sphere.errors.default_status) = 500; // Default status for all values
USER_ERROR_UNSPECIFIED = 0;
USER_ERROR_NOT_FOUND = 1001 [(sphere.errors.options) = {
status: 404
message: "用户不存在"
}];
USER_ERROR_INVALID_EMAIL = 1002 [(sphere.errors.options) = {
status: 400
message: "邮箱格式不正确"
}];
USER_ERROR_PERMISSION_DENIED = 1003 [(sphere.errors.options) = {
status: 403
message: "权限不足"
}];
}enum PaymentError {
option (sphere.errors.default_status) = 500;
PAYMENT_ERROR_UNSPECIFIED = 0;
PAYMENT_ERROR_INSUFFICIENT_FUNDS = 2001 [(sphere.errors.options) = {
status: 400
reason: "insufficient_funds"
message: "账户余额不足"
}];
PAYMENT_ERROR_CARD_EXPIRED = 2002 [(sphere.errors.options) = {
status: 400
reason: "card_expired"
message: "信用卡已过期"
}];
PAYMENT_ERROR_PROCESSING_FAILED = 2003 [(sphere.errors.options) = {
status: 502
reason: "processing_failed"
message: "支付处理失败,请稍后重试"
}];
}Add this dependency to your buf.yaml:
version: v2
deps:
- buf.build/go-sphere/errorsConfigure code generation in buf.gen.yaml:
version: v2
managed:
enabled: true
disable:
- file_option: go_package_prefix
module: buf.build/go-sphere/errors
plugins:
- local: protoc-gen-sphere-errors
out: api
opt: paths=source_relativeWhen used with protoc-gen-sphere-errors, the following Go methods are generated for each error enum:
Error() string- Returns the reason if specified, otherwise"EnumName_VALUE_NAME"GetCode() int32- Returns the error code (enum numeric value)GetStatus() int32- Returns the HTTP status codeGetMessage() string- Returns the human-readable messageJoin(errs ...error) error- Wraps the enum error with additional errorsJoinWithMessage(msg string, errs ...error) error- Wraps with a custom message
Usage examples:
// Direct error return
return nil, apiv1.UserError_USER_ERROR_NOT_FOUND
// With error wrapping (puts the enum error first in the chain)
if err != nil {
return nil, apiv1.UserError_USER_ERROR_NOT_FOUND.Join(err)
}
// With custom message
return nil, apiv1.UserError_USER_ERROR_NOT_FOUND.JoinWithMessage("User ID: 123 not found", err)The Go package github.com/go-sphere/errors/sphere/errors (the same package as
the generated extension types, which every .pb.go importing
sphere/errors/errors.proto already links) also provides the constructor that
the generated Join and JoinWithMessage helpers call by default:
func NewError(status, code int32, message string, err error) error- The returned error implements
Error() string,Unwrap() error,GetStatus() int32,GetCode() int32andGetMessage() string. Error()returnserr.Error(), andUnwrap()returnserr, soerrors.Is/errors.Assee the enum value and every joined cause.- When
erris nil, a default error with the texthttp.StatusText(status)is used ("Unknown error"when the status has no standard text). messageis stored as given; no fallback is applied.
These semantics match httpx.NewError. Adapters such as
github.com/go-sphere/httpx classify
errors through the GetStatus/GetCode/GetMessage methods rather than a
concrete type, so httpx.ParseError, ClassifyError and RenderError treat
the result exactly like an httpx.NewError value. Packages that only define
error codes therefore depend on this module (stdlib and protobuf only), not on
an HTTP adapter.
default_status: Sets the default HTTP status code for all enum values that don't specify their own status
status: HTTP status code (overrides default_status)reason: Optional machine-readable reason code (used as the Error() string when provided; otherwise uses "EnumName_VALUE_NAME")message: Human-readable error message for client display
- Use meaningful error codes: Choose enum values that clearly indicate the error type
- Set appropriate HTTP status codes: Use standard HTTP status codes (400, 401, 403, 404, 500, etc.)
- Provide clear messages: Write user-friendly error messages in the appropriate language
- Use reasons for API consumers: Include reason strings for programmatic error handling
- Group related errors: Keep related errors in the same enum for better organization
400: Bad Request - Client error, invalid input401: Unauthorized - Authentication required403: Forbidden - Permission denied404: Not Found - Resource doesn't exist409: Conflict - Resource conflict422: Unprocessable Entity - Validation failed429: Too Many Requests - Rate limiting500: Internal Server Error - Server-side error502: Bad Gateway - External service error503: Service Unavailable - Service temporarily down