go-tarantool icon indicating copy to clipboard operation
go-tarantool copied to clipboard

v3: new design for go-tarantool errors

Open bigbes opened this issue 1 month ago • 0 comments

Overview

We aim to overhaul the error design in the go-tarantool client library to follow Go’s standard error handling patterns as closely as possible. This will improve debuggability, testability, interoperability with standard library functions like errors.Is and errors.As, and overall developer experience for users of the package.

This effort is inspired by Go’s official guidance on error handling and best practices from the community (see references below).

Goals

  1. Adopt Go’s error wrapping conventions

    • Implement the Unwrap() error method on custom error types to support error unwrapping.
    • Avoid implementing Is(target error) bool unless absolutely necessary for complex matching logic.
  2. Introduce sentinel errors Define clear, exported, package-level sentinel errors for common failure modes:

    var (
        ErrConnectionNotReady = errors.New("client connection is not ready")
        ErrConnectionClosed   = errors.New("connection closed by client")
        // ... others as needed
    )
    
  3. Establish a layered error hierarchy Build a meaningful error chain that reflects both the origin and semantics of the error:

    ClientError -> RetryableError -> <Sentinel Error>
    
    • ClientError: wraps errors that originate from the client side (e.g., malformed requests).
    • RetryableError: indicates transient failures that may succeed on retry.
    • Sentinel errors provide the root cause and are used for comparison via errors.Is.
  4. Rename tarantool.Errortarantool.ServerError Clarify that this error type represents errors returned by the Tarantool server, not generic package errors.

  5. Provide ergonomic helper functions Add convenience functions to simplify error inspection:

    func IsRetryable(err error) bool      // equivalent to errors.Is(err, ErrRetryable)
    func IsClientError(err error) bool
    func IsServerError(err error) bool    // optional but helpful
    

    These should be implemented using errors.Is or errors.As under the hood.

  6. Improve error construction practices

    • Prefer using constructor functions (e.g., NewClientError(...)) over direct struct literals.
    • If struct initialization is unavoidable, always use keyed fields for clarity and future-proofing:
      err := &ClientError{
          Code:    42,
          Message: "something went wrong",
      }
      

References

To ensure consistency with Go community standards, please review the following:

Checklist

  • [ ] Define sentinel errors (ErrConnectionNotReady, etc.)
  • [ ] Implement ServerError (renamed from tarantool.Error)
  • [ ] Create ClientError and RetryableError wrapper types with Unwrap() support
  • [ ] Add helper functions: IsRetryable, IsClientError, IsServerError
  • [ ] Update all internal error creation paths to use constructors or keyed struct literals
  • [ ] Add unit tests verifying error chains and errors.Is/errors.As behavior
  • [ ] Update documentation and examples to reflect new error patterns
  • [ ] Update CHANGELOG.md and MIGRATION.md

bigbes avatar Oct 23 '25 00:10 bigbes