wrapcheck

repository·master·Indexed 18 days ago

https://github.com/tomarrell/wrapcheck

A Go linter that ensures errors from external packages are wrapped before being returned to improve debuggability. It can be used as a standalone CLI tool or as part of golangci-lint. Configuration via .wrapcheck.yaml allows users to customize ignored error signatures, packages, and interfaces using options such as ignoreSigs, ignorePackageGlobs, and ignoreInterfaceRegexps.

Tokens
1.9K
Snippets
12
Records
12
Agent score
14%

What's inside wrapcheck

  1. How Wrapcheck works: Identifying unwrapped external errors

    master

    Wrapcheck is a linter designed to ensure that errors originating from external packages are wrapped before being returned. This helps identify the source of an error during debugging by providing context in logs.

    The Problem: If you return an error from an external library directly, your logs might only show the library's error message (e.g., sql: error no rows), making it difficult to know which specific method or database call triggered it.

    The Solution: Wrap the error at the call site using functions like fmt.Errorf. This adds context to the error chain.

    Example of an unwrapped error (Linter Trigger):

    if err := db.conn.Get(&u, sql, userID); err != nil {
        return User{}, err // wrapcheck error: error returned from external package is unwrapped
    }

    Example of a wrapped error (Correct):

    if err := db.conn.Get(&u, sql, userID); err != nil {
        return User{}, fmt.Errorf("failed to get user by ID: %v", err) // No error!
    }
    // Correct way to handle external errors
    if _, err := tx.Exec(sql, name, email, city); err != nil {
      return fmt.Errorf("failed to insert user: %v", err)
    }
  2. Install Wrapcheck

    master

    Wrapcheck requires Go >= v1.22.0. You can install the CLI tool directly using go install or use it as part of the golangci-lint meta linter.

    To install the standalone CLI:

    $ go install github.com/tomarrell/wrapcheck/v2/cmd/wrapcheck@v2

    If using golangci-lint, configuration is managed via your .golangci.yaml file.

  3. Configure Wrapcheck via .wrapcheck.yaml

    master

    Wrapcheck can be configured using a .wrapcheck.yaml file located in your local directory or your home directory. This allows you to customize which error signatures, packages, or interfaces are ignored during analysis.

    Common configuration keys include:

    • ignoreSigs: Overrides the default set of ignored signature substrings.
    • extraIgnoreSigs: Extends the default/ignoreSigs set without replacing it.
    • ignoreSigRegexps: Regular expressions for signatures to ignore.
    • ignorePackageGlobs: Glob patterns for packages to skip entirely.
    • ignoreInterfaceRegexps: Regular expressions for interface names to ignore unwrapped errors.
    • reportInternalErrors: Boolean to determine if errors from within the package itself should be reported.
    ignoreSigs:
    - .Errorf(
    - errors.New(
    
    extraIgnoreSigs:
    - .CustomError(
    
    ignoreSigRegexps:
    - \.New.*Error\(
    
    ignorePackageGlobs:
    - encoding/*
    - github.com/pkg/*
    
    ignoreInterfaceRegexps:
    - ^(?i)c(?-i)ach(ing|e)
    
    reportInternalErrors: true
  4. Configure wrapcheck via .wrapcheck.yaml

    master

    wrapcheck can be configured using a YAML configuration file named .wrapcheck.yaml. The tool searches for this file in the following locations:

    1. $HOME/.wrapcheck/.wrapcheck.yaml
    2. The current working directory (.).

    If the configuration file is not found, the tool will proceed using default settings. If the file exists but contains invalid YAML, the tool will fail to start.

    # Example .wrapcheck.yaml
    ignoreSigs:
      - "pkg/errors/errors.Wrap"
      - "pkg/errors/errors.Wrapf"
    
    ignoreRegex:
      - "^pkg/errors/.*"
    
    additionalIgnoreSigs:
      - "custom/error/wrap"
  5. Configure ignoreInterfaceRegexps

    master

    The ignoreInterfaceRegexps option defines a list of regular expressions. If a regex matches an underlying interface name, wrapcheck will ignore unwrapped errors returned from a function whose call is defined on that interface.

    ignoreInterfaceRegexps:
    - ^(?i)c(?-i)ach(ing|e)
  6. Configure ignoreSigs

    master

    The ignoreSigs option accepts an array of strings representing substrings of signatures to ignore. Note: Setting this option will override the default set of ignored signatures. You can find the default set at the top of ./wrapcheck/wrapcheck.go.

    ignoreSigs:
    - .Errorf(
    - errors.New(
    - errors.Unwrap(
    - errors.Join(
    - .Wrap(
    - .Wrapf(
    - .WithMessage(
    - .WithMessagef(
    - .WithStack(
  7. Configure extraIgnoreSigs

    master

    The extraIgnoreSigs option accepts an array of strings specifying additional substrings of signatures to ignore. Unlike ignoreSigs, this option extends the default set (or the set specified in ignoreSigs) without replacing it entirely. This is useful for adding project-specific wrapping functions while retaining standard defaults.

    extraIgnoreSigs:
    - .CustomError(
    - .SpecificWrap(
  8. Configure ignoreSigRegexps

    master

    The ignoreSigRegexps option accepts an array of strings which are treated as regular expressions of signatures to ignore. This provides more flexibility than simple substring matching used in ignoreSigs.

    ignoreSigRegexps:
    - \.New.*Error\(
  9. Configure ignorePackageGlobs

    master

    The ignorePackageGlobs option accepts an array of glob patterns. If a pattern matches the package of a function returning an error, wrapcheck will skip analysis for that error. This is useful for broadly ignoring specific third-party packages or subpackages. There are no default values for this setting.

    ignorePackageGlobs:
    - encoding/*
    - github.com/pkg/*
  10. Reference wrapcheck configuration keys

    master

    The following configuration keys are used to control which error wrapping signatures are ignored by the linter. These are unmarshaled into a wrapcheck.WrapcheckConfig object.

    ignoreSigs: []string        # An array of strings which specify substrings of signatures to ignore. If this is set, it will override the default set.
    ignoreRegex: []string       # An array of strings specifying regular expressions of signatures to ignore.
    additionalIgnoreSigs: []string # An array of strings specifying additional substrings of signatures to ignore. This extends the default set (or the set specified in ignoreSigs) without replacing it entirely.