errors.go raw

   1  package mapstructure
   2  
   3  import (
   4  	"errors"
   5  	"fmt"
   6  	"net"
   7  	"net/url"
   8  	"reflect"
   9  	"strconv"
  10  	"strings"
  11  	"time"
  12  )
  13  
  14  // Error interface is implemented by all errors emitted by mapstructure.
  15  //
  16  // Use [errors.As] to check if an error implements this interface.
  17  type Error interface {
  18  	error
  19  
  20  	mapstructure()
  21  }
  22  
  23  // DecodeError is a generic error type that holds information about
  24  // a decoding error together with the name of the field that caused the error.
  25  type DecodeError struct {
  26  	name string
  27  	err  error
  28  }
  29  
  30  func newDecodeError(name string, err error) *DecodeError {
  31  	return &DecodeError{
  32  		name: name,
  33  		err:  err,
  34  	}
  35  }
  36  
  37  func (e *DecodeError) Name() string {
  38  	return e.name
  39  }
  40  
  41  func (e *DecodeError) Unwrap() error {
  42  	return e.err
  43  }
  44  
  45  func (e *DecodeError) Error() string {
  46  	return fmt.Sprintf("'%s' %s", e.name, e.err)
  47  }
  48  
  49  func (*DecodeError) mapstructure() {}
  50  
  51  // ParseError is an error type that indicates a value could not be parsed
  52  // into the expected type.
  53  type ParseError struct {
  54  	Expected reflect.Value
  55  	Value    any
  56  	Err      error
  57  }
  58  
  59  func (e *ParseError) Error() string {
  60  	return fmt.Sprintf("cannot parse value as '%s': %s", e.Expected.Type(), e.Err)
  61  }
  62  
  63  func (*ParseError) mapstructure() {}
  64  
  65  // UnconvertibleTypeError is an error type that indicates a value could not be
  66  // converted to the expected type.
  67  type UnconvertibleTypeError struct {
  68  	Expected reflect.Value
  69  	Value    any
  70  }
  71  
  72  func (e *UnconvertibleTypeError) Error() string {
  73  	return fmt.Sprintf(
  74  		"expected type '%s', got unconvertible type '%s'",
  75  		e.Expected.Type(),
  76  		reflect.TypeOf(e.Value),
  77  	)
  78  }
  79  
  80  func (*UnconvertibleTypeError) mapstructure() {}
  81  
  82  func wrapStrconvNumError(err error) error {
  83  	if err == nil {
  84  		return nil
  85  	}
  86  
  87  	if err, ok := err.(*strconv.NumError); ok {
  88  		return &strconvNumError{Err: err}
  89  	}
  90  
  91  	return err
  92  }
  93  
  94  type strconvNumError struct {
  95  	Err *strconv.NumError
  96  }
  97  
  98  func (e *strconvNumError) Error() string {
  99  	return "strconv." + e.Err.Func + ": " + e.Err.Err.Error()
 100  }
 101  
 102  func (e *strconvNumError) Unwrap() error { return e.Err }
 103  
 104  func wrapUrlError(err error) error {
 105  	if err == nil {
 106  		return nil
 107  	}
 108  
 109  	if err, ok := err.(*url.Error); ok {
 110  		return &urlError{Err: err}
 111  	}
 112  
 113  	return err
 114  }
 115  
 116  type urlError struct {
 117  	Err *url.Error
 118  }
 119  
 120  func (e *urlError) Error() string {
 121  	return fmt.Sprintf("%s", e.Err.Err)
 122  }
 123  
 124  func (e *urlError) Unwrap() error { return e.Err }
 125  
 126  func wrapNetParseError(err error) error {
 127  	if err == nil {
 128  		return nil
 129  	}
 130  
 131  	if err, ok := err.(*net.ParseError); ok {
 132  		return &netParseError{Err: err}
 133  	}
 134  
 135  	return err
 136  }
 137  
 138  type netParseError struct {
 139  	Err *net.ParseError
 140  }
 141  
 142  func (e *netParseError) Error() string {
 143  	return "invalid " + e.Err.Type
 144  }
 145  
 146  func (e *netParseError) Unwrap() error { return e.Err }
 147  
 148  func wrapTimeParseError(err error) error {
 149  	if err == nil {
 150  		return nil
 151  	}
 152  
 153  	if err, ok := err.(*time.ParseError); ok {
 154  		return &timeParseError{Err: err}
 155  	}
 156  
 157  	return err
 158  }
 159  
 160  type timeParseError struct {
 161  	Err *time.ParseError
 162  }
 163  
 164  func (e *timeParseError) Error() string {
 165  	if e.Err.Message == "" {
 166  		return fmt.Sprintf("parsing time as %q: cannot parse as %q", e.Err.Layout, e.Err.LayoutElem)
 167  	}
 168  
 169  	return "parsing time " + e.Err.Message
 170  }
 171  
 172  func (e *timeParseError) Unwrap() error { return e.Err }
 173  
 174  func wrapNetIPParseAddrError(err error) error {
 175  	if err == nil {
 176  		return nil
 177  	}
 178  
 179  	if errMsg := err.Error(); strings.HasPrefix(errMsg, "ParseAddr") {
 180  		errPieces := strings.Split(errMsg, ": ")
 181  
 182  		return fmt.Errorf("ParseAddr: %s", errPieces[len(errPieces)-1])
 183  	}
 184  
 185  	return err
 186  }
 187  
 188  func wrapNetIPParseAddrPortError(err error) error {
 189  	if err == nil {
 190  		return nil
 191  	}
 192  
 193  	errMsg := err.Error()
 194  	if strings.HasPrefix(errMsg, "invalid port ") {
 195  		return errors.New("invalid port")
 196  	} else if strings.HasPrefix(errMsg, "invalid ip:port ") {
 197  		return errors.New("invalid ip:port")
 198  	}
 199  
 200  	return err
 201  }
 202  
 203  func wrapNetIPParsePrefixError(err error) error {
 204  	if err == nil {
 205  		return nil
 206  	}
 207  
 208  	if errMsg := err.Error(); strings.HasPrefix(errMsg, "netip.ParsePrefix") {
 209  		errPieces := strings.Split(errMsg, ": ")
 210  
 211  		return fmt.Errorf("netip.ParsePrefix: %s", errPieces[len(errPieces)-1])
 212  	}
 213  
 214  	return err
 215  }
 216  
 217  func wrapTimeParseDurationError(err error) error {
 218  	if err == nil {
 219  		return nil
 220  	}
 221  
 222  	errMsg := err.Error()
 223  	if strings.HasPrefix(errMsg, "time: unknown unit ") {
 224  		return errors.New("time: unknown unit")
 225  	} else if strings.HasPrefix(errMsg, "time: ") {
 226  		idx := strings.LastIndex(errMsg, " ")
 227  
 228  		return errors.New(errMsg[:idx])
 229  	}
 230  
 231  	return err
 232  }
 233  
 234  func wrapTimeParseLocationError(err error) error {
 235  	if err == nil {
 236  		return nil
 237  	}
 238  	errMsg := err.Error()
 239  	if strings.Contains(errMsg, "unknown time zone") || strings.HasPrefix(errMsg, "time: unknown format") {
 240  		return fmt.Errorf("invalid time zone format: %w", err)
 241  	}
 242  
 243  	return err
 244  }
 245