Skip to content

v3: new design for go-tarantool errors #469

@bigbes

Description

@bigbes

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions