liveBook · Manning

Error type

As explained in Learn Go with Pocket-Sized Projects

A custom error is an application-defined error value or type representing a specific failure condition.

An error type represents a specific failure condition with structured information. In a business layer, it lets validation report what went wrong without coupling domain code to gRPC status codes. section 10.3.1 section 10.7.3

Validate input with a typed error

Define an error carrying the invalid field and reason, then return it from validation: `type InvalidInputError struct { field, reason string }`; `func (e InvalidInputError) Error() string { return fmt.Sprintf("invalid input in field %s: %s", e.field, e.reason) }`. A validator can trim the name and return `InvalidInputError{field: "name", reason: "cannot be empty"}` when it remains blank. section 10.3.1

Use error types to preserve boundaries and make failures testable:

  • Keep domain errors independent of transport details; let the API layer translate invalid input into gRPC code 3, INVALID_ARGUMENT. section 10.3.1
  • Translate repository-specific errors with `errors.Is`; map a missing habit to `codes.NotFound` and unexpected failures to `codes.Internal`. section 10.7.3
  • Test the concrete error with `assert.ErrorAs`, alongside valid complete and partially filled inputs. section 10.3.1
Listing 10.14 errors.go: Typed error for invalid input
// InvalidInputError is returned when user-input data is invalid.
type InvalidInputError struct {
    field  string
    reason string #1
}

// Error implements error.
func (e InvalidInputError) Error() string {
    return fmt.Sprintf("invalid input in field %s: %s", e.field, e.reason)
}

Inspect the complete typed error definition and its Error method. section 10.3.1

err := habit.Tick(ctx, s.db, s.db, habit.ID(request.HabitId), time.Now())
if err != nil {
    switch {
    case errors.Is(err, r.ErrNotFound):
        return nil, status.Errorf(codes.NotFound, 
            "couldn't find habit %q in repository", request.HabitId)
    default:
        return nil, status.Errorf(codes.Internal, 
            "cannot tick habit %q: %s", request.HabitId, err.Error())
    }
}

Inspect transport-level conversion from a domain error to a gRPC status. section 10.7.3

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Defines error fields and Error methods, demonstrates validation and status conversion, and tests ErrorAs without exploring broader error hierarchies.
Examples
Uses InvalidInputError for blank habit names and a not-found repository error when ticking an unknown habit.
What you can do after
Apply it via Go error types, errors.Is, ErrorAs, and gRPC status conversion to validate inputs and expose stable failures.
How it connects
Connects error types with domain layers, validation, errors.Is, gRPC status codes, and unit testing.

Also explained in

Compare how 5 books explain error type →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Go with Pocket-Sized Projects. The section links point to the parts of the book it draws on.