Go 1.13 is out. Here are the features I’m excited about.

1. Error Wrapping

Finally, standard error wrapping!

Before:

if err != nil {
    return fmt.Errorf("failed to process: %v", err)
}

Problem: Lost the original error. Can’t use errors.Is() or errors.As().

After:

if err != nil {
    return fmt.Errorf("failed to process: %w", err)
}

The %w verb wraps the error.

errors.Is()

Check if error is a specific type:

var ErrNotFound = errors.New("not found")

func GetUser(id string) (*User, error) {
    user, err := db.Find(id)
    if err != nil {
        return nil, fmt.Errorf("get user: %w", ErrNotFound)
    }
    return user, nil
}

// Usage
user, err := GetUser("123")
if errors.Is(err, ErrNotFound) {
    // Handle not found
}

Works even if error is wrapped multiple times!

errors.As()

Extract specific error type:

type ValidationError struct {
    Field string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", e.Field, e.Message)
}

// Usage
var validationErr *ValidationError
if errors.As(err, &validationErr) {
    fmt.Printf("Validation failed on field: %s\n", validationErr.Field)
}

errors.Unwrap()

Get the wrapped error:

err := fmt.Errorf("outer: %w", innerErr)
unwrapped := errors.Unwrap(err)
// unwrapped == innerErr

Real-World Example

package user

import (
    "database/sql"
    "errors"
    "fmt"
)

var (
    ErrNotFound = errors.New("user not found")
    ErrInvalid  = errors.New("invalid user data")
)

type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", e.Field, e.Message)
}

func GetUser(id string) (*User, error) {
    if id == "" {
        return nil, &ValidationError{
            Field:   "id",
            Message: "cannot be empty",
        }
    }
    
    user, err := db.FindUser(id)
    if err == sql.ErrNoRows {
        return nil, fmt.Errorf("get user %s: %w", id, ErrNotFound)
    }
    if err != nil {
        return nil, fmt.Errorf("get user %s: %w", id, err)
    }
    
    return user, nil
}

// Usage
user, err := GetUser("")
if err != nil {
    var validationErr *ValidationError
    if errors.As(err, &validationErr) {
        fmt.Printf("Validation error: %s\n", validationErr.Field)
        return
    }
    
    if errors.Is(err, ErrNotFound) {
        fmt.Println("User not found")
        return
    }
    
    fmt.Printf("Unexpected error: %v\n", err)
}

2. Module Improvements

GOPRIVATE

For private repositories:

export GOPRIVATE=github.com/mycompany/*

No more proxy for private repos.

Module Mirror

Default proxy: proxy.golang.org

# Disable proxy
export GOPROXY=direct

# Use custom proxy
export GOPROXY=https://goproxy.io

go get Improvements

# Get latest version
go get github.com/pkg/errors

# Get specific version
go get github.com/pkg/errors@v0.9.1

# Get latest patch
go get github.com/pkg/errors@v0.9

# Upgrade all dependencies
go get -u ./...

# Upgrade only patch versions
go get -u=patch ./...

3. Number Literals

Binary Literals

b := 0b1010  // 10 in decimal

Octal Literals

// Old way
o := 0755

// New way (clearer)
o := 0o755

Hex Literals

h := 0xFF

Digit Separators

Make large numbers readable:

million := 1_000_000
billion := 1_000_000_000

hex := 0x_FF_FF_FF_FF

binary := 0b_1010_1010_1010_1010

4. TLS 1.3 by Default

TLS 1.3 is now the default for crypto/tls.

Faster handshakes, better security.

5. Improved defer Performance

defer is now faster (30% in some cases).

Our Migration

Upgraded all projects from Go 1.12 to 1.13.

Changes We Made

1. Updated Error Handling

// Before
if err != nil {
    return fmt.Errorf("failed: %v", err)
}

// After
if err != nil {
    return fmt.Errorf("failed: %w", err)
}

2. Added Error Checks

// Before
if err != nil {
    if err.Error() == "not found" {
        // Handle
    }
}

// After
if errors.Is(err, ErrNotFound) {
    // Handle
}

3. Used Digit Separators

// Before
timeout := 30000000000  // 30 seconds in nanoseconds

// After
timeout := 30_000_000_000  // Much clearer!

Should You Upgrade?

Yes:

  • Error wrapping is a game-changer
  • Module improvements are useful
  • No breaking changes

We upgraded in one day. Smooth process.

The Verdict

Go 1.13 is a solid release. Error wrapping alone makes it worth upgrading.

If you’re on Go 1.11 or 1.12, upgrade now.

Questions? Let me know!