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