Source file
src/net/error_test.go
Documentation: net
1
2
3
4
5
6
7
8 package net
9
10 import (
11 "context"
12 "errors"
13 "fmt"
14 "internal/poll"
15 "io"
16 "io/fs"
17 "net/internal/socktest"
18 "os"
19 "runtime"
20 "strings"
21 "testing"
22 "time"
23 )
24
25 func (e *OpError) isValid() error {
26 if e.Op == "" {
27 return fmt.Errorf("OpError.Op is empty: %v", e)
28 }
29 if e.Net == "" {
30 return fmt.Errorf("OpError.Net is empty: %v", e)
31 }
32 for _, addr := range []Addr{e.Source, e.Addr} {
33 switch addr := addr.(type) {
34 case nil:
35 case *TCPAddr:
36 if addr == nil {
37 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
38 }
39 case *UDPAddr:
40 if addr == nil {
41 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
42 }
43 case *IPAddr:
44 if addr == nil {
45 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
46 }
47 case *IPNet:
48 if addr == nil {
49 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
50 }
51 case *UnixAddr:
52 if addr == nil {
53 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
54 }
55 case *pipeAddr:
56 if addr == nil {
57 return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
58 }
59 case fileAddr:
60 if addr == "" {
61 return fmt.Errorf("OpError.Source or Addr is empty: %#v, %v", addr, e)
62 }
63 default:
64 return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e)
65 }
66 }
67 if e.Err == nil {
68 return fmt.Errorf("OpError.Err is empty: %v", e)
69 }
70 return nil
71 }
72
73
74
75
76 func parseDialError(nestedErr error) error {
77 if nestedErr == nil {
78 return nil
79 }
80
81 switch err := nestedErr.(type) {
82 case *OpError:
83 if err := err.isValid(); err != nil {
84 return err
85 }
86 nestedErr = err.Err
87 goto second
88 }
89 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
90
91 second:
92 if isPlatformError(nestedErr) {
93 return nil
94 }
95 switch err := nestedErr.(type) {
96 case *AddrError, addrinfoErrno, *timeoutError, *DNSError, InvalidAddrError, *ParseError, *poll.DeadlineExceededError, UnknownNetworkError:
97 return nil
98 case *os.SyscallError:
99 nestedErr = err.Err
100 goto third
101 case *fs.PathError:
102 nestedErr = err.Err
103 goto third
104 }
105 switch nestedErr {
106 case errCanceled, ErrClosed, errMissingAddress, errNoSuitableAddress,
107 context.DeadlineExceeded, context.Canceled:
108 return nil
109 }
110 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
111
112 third:
113 if isPlatformError(nestedErr) {
114 return nil
115 }
116 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
117 }
118
119 var dialErrorTests = []struct {
120 network, address string
121 }{
122 {"foo", ""},
123 {"bar", "baz"},
124 {"datakit", "mh/astro/r70"},
125 {"tcp", ""},
126 {"tcp", "127.0.0.1:☺"},
127 {"tcp", "no-such-name:80"},
128 {"tcp", "mh/astro/r70:http"},
129
130 {"tcp", JoinHostPort("127.0.0.1", "-1")},
131 {"tcp", JoinHostPort("127.0.0.1", "123456789")},
132 {"udp", JoinHostPort("127.0.0.1", "-1")},
133 {"udp", JoinHostPort("127.0.0.1", "123456789")},
134 {"ip:icmp", "127.0.0.1"},
135
136 {"unix", "/path/to/somewhere"},
137 {"unixgram", "/path/to/somewhere"},
138 {"unixpacket", "/path/to/somewhere"},
139 }
140
141 func TestDialError(t *testing.T) {
142 switch runtime.GOOS {
143 case "plan9":
144 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
145 }
146
147 origTestHookLookupIP := testHookLookupIP
148 defer func() { testHookLookupIP = origTestHookLookupIP }()
149 testHookLookupIP = func(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
150 return nil, &DNSError{Err: "dial error test", Name: "name", Server: "server", IsTimeout: true}
151 }
152 sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
153 return nil, errOpNotSupported
154 })
155 defer sw.Set(socktest.FilterConnect, nil)
156
157 d := Dialer{Timeout: someTimeout}
158 for i, tt := range dialErrorTests {
159 c, err := d.Dial(tt.network, tt.address)
160 if err == nil {
161 t.Errorf("#%d: should fail; %s:%s->%s", i, c.LocalAddr().Network(), c.LocalAddr(), c.RemoteAddr())
162 c.Close()
163 continue
164 }
165 if tt.network == "tcp" || tt.network == "udp" {
166 nerr := err
167 if op, ok := nerr.(*OpError); ok {
168 nerr = op.Err
169 }
170 if sys, ok := nerr.(*os.SyscallError); ok {
171 nerr = sys.Err
172 }
173 if nerr == errOpNotSupported {
174 t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address)
175 continue
176 }
177 }
178 if c != nil {
179 t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
180 }
181 if err = parseDialError(err); err != nil {
182 t.Errorf("#%d: %v", i, err)
183 continue
184 }
185 }
186 }
187
188 func TestProtocolDialError(t *testing.T) {
189 switch runtime.GOOS {
190 case "solaris", "illumos":
191 t.Skipf("not supported on %s", runtime.GOOS)
192 }
193
194 for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
195 var err error
196 switch network {
197 case "tcp":
198 _, err = DialTCP(network, nil, &TCPAddr{Port: 1 << 16})
199 case "udp":
200 _, err = DialUDP(network, nil, &UDPAddr{Port: 1 << 16})
201 case "ip:4294967296":
202 _, err = DialIP(network, nil, nil)
203 case "unix", "unixpacket", "unixgram":
204 _, err = DialUnix(network, nil, &UnixAddr{Name: "//"})
205 }
206 if err == nil {
207 t.Errorf("%s: should fail", network)
208 continue
209 }
210 if err = parseDialError(err); err != nil {
211 t.Errorf("%s: %v", network, err)
212 continue
213 }
214 }
215 }
216
217 func TestDialAddrError(t *testing.T) {
218 switch runtime.GOOS {
219 case "plan9":
220 t.Skipf("not supported on %s", runtime.GOOS)
221 }
222 if !supportsIPv4() || !supportsIPv6() {
223 t.Skip("both IPv4 and IPv6 are required")
224 }
225
226 for _, tt := range []struct {
227 network string
228 lit string
229 addr *TCPAddr
230 }{
231 {"tcp4", "::1", nil},
232 {"tcp4", "", &TCPAddr{IP: IPv6loopback}},
233
234
235
236 {"tcp6", "", &TCPAddr{IP: IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}}},
237 } {
238 var err error
239 var c Conn
240 var op string
241 if tt.lit != "" {
242 c, err = Dial(tt.network, JoinHostPort(tt.lit, "0"))
243 op = fmt.Sprintf("Dial(%q, %q)", tt.network, JoinHostPort(tt.lit, "0"))
244 } else {
245 c, err = DialTCP(tt.network, nil, tt.addr)
246 op = fmt.Sprintf("DialTCP(%q, %q)", tt.network, tt.addr)
247 }
248 if err == nil {
249 c.Close()
250 t.Errorf("%s succeeded, want error", op)
251 continue
252 }
253 if perr := parseDialError(err); perr != nil {
254 t.Errorf("%s: %v", op, perr)
255 continue
256 }
257 operr := err.(*OpError).Err
258 aerr, ok := operr.(*AddrError)
259 if !ok {
260 t.Errorf("%s: %v is %T, want *AddrError", op, err, operr)
261 continue
262 }
263 want := tt.lit
264 if tt.lit == "" {
265 want = tt.addr.IP.String()
266 }
267 if aerr.Addr != want {
268 t.Errorf("%s: %v, error Addr=%q, want %q", op, err, aerr.Addr, want)
269 }
270 }
271 }
272
273 var listenErrorTests = []struct {
274 network, address string
275 }{
276 {"foo", ""},
277 {"bar", "baz"},
278 {"datakit", "mh/astro/r70"},
279 {"tcp", "127.0.0.1:☺"},
280 {"tcp", "no-such-name:80"},
281 {"tcp", "mh/astro/r70:http"},
282
283 {"tcp", JoinHostPort("127.0.0.1", "-1")},
284 {"tcp", JoinHostPort("127.0.0.1", "123456789")},
285
286 {"unix", "/path/to/somewhere"},
287 {"unixpacket", "/path/to/somewhere"},
288 }
289
290 func TestListenError(t *testing.T) {
291 switch runtime.GOOS {
292 case "plan9":
293 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
294 }
295
296 origTestHookLookupIP := testHookLookupIP
297 defer func() { testHookLookupIP = origTestHookLookupIP }()
298 testHookLookupIP = func(_ context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
299 return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
300 }
301 sw.Set(socktest.FilterListen, func(so *socktest.Status) (socktest.AfterFilter, error) {
302 return nil, errOpNotSupported
303 })
304 defer sw.Set(socktest.FilterListen, nil)
305
306 for i, tt := range listenErrorTests {
307 ln, err := Listen(tt.network, tt.address)
308 if err == nil {
309 t.Errorf("#%d: should fail; %s:%s->", i, ln.Addr().Network(), ln.Addr())
310 ln.Close()
311 continue
312 }
313 if tt.network == "tcp" {
314 nerr := err
315 if op, ok := nerr.(*OpError); ok {
316 nerr = op.Err
317 }
318 if sys, ok := nerr.(*os.SyscallError); ok {
319 nerr = sys.Err
320 }
321 if nerr == errOpNotSupported {
322 t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address)
323 continue
324 }
325 }
326 if ln != nil {
327 t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln)
328 }
329 if err = parseDialError(err); err != nil {
330 t.Errorf("#%d: %v", i, err)
331 continue
332 }
333 }
334 }
335
336 var listenPacketErrorTests = []struct {
337 network, address string
338 }{
339 {"foo", ""},
340 {"bar", "baz"},
341 {"datakit", "mh/astro/r70"},
342 {"udp", "127.0.0.1:☺"},
343 {"udp", "no-such-name:80"},
344 {"udp", "mh/astro/r70:http"},
345
346 {"udp", JoinHostPort("127.0.0.1", "-1")},
347 {"udp", JoinHostPort("127.0.0.1", "123456789")},
348 }
349
350 func TestListenPacketError(t *testing.T) {
351 switch runtime.GOOS {
352 case "plan9":
353 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
354 }
355
356 origTestHookLookupIP := testHookLookupIP
357 defer func() { testHookLookupIP = origTestHookLookupIP }()
358 testHookLookupIP = func(_ context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
359 return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
360 }
361
362 for i, tt := range listenPacketErrorTests {
363 c, err := ListenPacket(tt.network, tt.address)
364 if err == nil {
365 t.Errorf("#%d: should fail; %s:%s->", i, c.LocalAddr().Network(), c.LocalAddr())
366 c.Close()
367 continue
368 }
369 if c != nil {
370 t.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c, c)
371 }
372 if err = parseDialError(err); err != nil {
373 t.Errorf("#%d: %v", i, err)
374 continue
375 }
376 }
377 }
378
379 func TestProtocolListenError(t *testing.T) {
380 switch runtime.GOOS {
381 case "plan9":
382 t.Skipf("not supported on %s", runtime.GOOS)
383 }
384
385 for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
386 var err error
387 switch network {
388 case "tcp":
389 _, err = ListenTCP(network, &TCPAddr{Port: 1 << 16})
390 case "udp":
391 _, err = ListenUDP(network, &UDPAddr{Port: 1 << 16})
392 case "ip:4294967296":
393 _, err = ListenIP(network, nil)
394 case "unix", "unixpacket":
395 _, err = ListenUnix(network, &UnixAddr{Name: "//"})
396 case "unixgram":
397 _, err = ListenUnixgram(network, &UnixAddr{Name: "//"})
398 }
399 if err == nil {
400 t.Errorf("%s: should fail", network)
401 continue
402 }
403 if err = parseDialError(err); err != nil {
404 t.Errorf("%s: %v", network, err)
405 continue
406 }
407 }
408 }
409
410
411
412
413 func parseReadError(nestedErr error) error {
414 if nestedErr == nil {
415 return nil
416 }
417
418 switch err := nestedErr.(type) {
419 case *OpError:
420 if err := err.isValid(); err != nil {
421 return err
422 }
423 nestedErr = err.Err
424 goto second
425 }
426 if nestedErr == io.EOF {
427 return nil
428 }
429 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
430
431 second:
432 if isPlatformError(nestedErr) {
433 return nil
434 }
435 switch err := nestedErr.(type) {
436 case *os.SyscallError:
437 nestedErr = err.Err
438 goto third
439 }
440 switch nestedErr {
441 case ErrClosed, errTimeout, poll.ErrNotPollable, os.ErrDeadlineExceeded:
442 return nil
443 }
444 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
445
446 third:
447 if isPlatformError(nestedErr) {
448 return nil
449 }
450 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
451 }
452
453
454
455
456 func parseWriteError(nestedErr error) error {
457 if nestedErr == nil {
458 return nil
459 }
460
461 switch err := nestedErr.(type) {
462 case *OpError:
463 if err := err.isValid(); err != nil {
464 return err
465 }
466 nestedErr = err.Err
467 goto second
468 }
469 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
470
471 second:
472 if isPlatformError(nestedErr) {
473 return nil
474 }
475 switch err := nestedErr.(type) {
476 case *AddrError, addrinfoErrno, *timeoutError, *DNSError, InvalidAddrError, *ParseError, *poll.DeadlineExceededError, UnknownNetworkError:
477 return nil
478 case *os.SyscallError:
479 nestedErr = err.Err
480 goto third
481 }
482 switch nestedErr {
483 case errCanceled, ErrClosed, errMissingAddress, errTimeout, os.ErrDeadlineExceeded, ErrWriteToConnected, io.ErrUnexpectedEOF:
484 return nil
485 }
486 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
487
488 third:
489 if isPlatformError(nestedErr) {
490 return nil
491 }
492 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
493 }
494
495
496
497
498 func parseCloseError(nestedErr error, isShutdown bool) error {
499 if nestedErr == nil {
500 return nil
501 }
502
503
504
505
506
507
508 want := "use of closed network connection"
509 if !isShutdown && !strings.Contains(nestedErr.Error(), want) {
510 return fmt.Errorf("error string %q does not contain expected string %q", nestedErr, want)
511 }
512
513 if !isShutdown && !errors.Is(nestedErr, ErrClosed) {
514 return fmt.Errorf("errors.Is(%v, errClosed) returns false, want true", nestedErr)
515 }
516
517 switch err := nestedErr.(type) {
518 case *OpError:
519 if err := err.isValid(); err != nil {
520 return err
521 }
522 nestedErr = err.Err
523 goto second
524 }
525 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
526
527 second:
528 if isPlatformError(nestedErr) {
529 return nil
530 }
531 switch err := nestedErr.(type) {
532 case *os.SyscallError:
533 nestedErr = err.Err
534 goto third
535 case *fs.PathError:
536 nestedErr = err.Err
537 goto third
538 }
539 switch nestedErr {
540 case ErrClosed:
541 return nil
542 }
543 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
544
545 third:
546 if isPlatformError(nestedErr) {
547 return nil
548 }
549 switch nestedErr {
550 case fs.ErrClosed:
551 return nil
552 }
553 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
554 }
555
556 func TestCloseError(t *testing.T) {
557 ln, err := newLocalListener("tcp")
558 if err != nil {
559 t.Fatal(err)
560 }
561 defer ln.Close()
562 c, err := Dial(ln.Addr().Network(), ln.Addr().String())
563 if err != nil {
564 t.Fatal(err)
565 }
566 defer c.Close()
567
568 for i := 0; i < 3; i++ {
569 err = c.(*TCPConn).CloseRead()
570 if perr := parseCloseError(err, true); perr != nil {
571 t.Errorf("#%d: %v", i, perr)
572 }
573 }
574 for i := 0; i < 3; i++ {
575 err = c.(*TCPConn).CloseWrite()
576 if perr := parseCloseError(err, true); perr != nil {
577 t.Errorf("#%d: %v", i, perr)
578 }
579 }
580 for i := 0; i < 3; i++ {
581 err = c.Close()
582 if perr := parseCloseError(err, false); perr != nil {
583 t.Errorf("#%d: %v", i, perr)
584 }
585 err = ln.Close()
586 if perr := parseCloseError(err, false); perr != nil {
587 t.Errorf("#%d: %v", i, perr)
588 }
589 }
590
591 pc, err := ListenPacket("udp", "127.0.0.1:0")
592 if err != nil {
593 t.Fatal(err)
594 }
595 defer pc.Close()
596
597 for i := 0; i < 3; i++ {
598 err = pc.Close()
599 if perr := parseCloseError(err, false); perr != nil {
600 t.Errorf("#%d: %v", i, perr)
601 }
602 }
603 }
604
605
606
607
608 func parseAcceptError(nestedErr error) error {
609 if nestedErr == nil {
610 return nil
611 }
612
613 switch err := nestedErr.(type) {
614 case *OpError:
615 if err := err.isValid(); err != nil {
616 return err
617 }
618 nestedErr = err.Err
619 goto second
620 }
621 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
622
623 second:
624 if isPlatformError(nestedErr) {
625 return nil
626 }
627 switch err := nestedErr.(type) {
628 case *os.SyscallError:
629 nestedErr = err.Err
630 goto third
631 case *fs.PathError:
632 nestedErr = err.Err
633 goto third
634 }
635 switch nestedErr {
636 case ErrClosed, errTimeout, poll.ErrNotPollable, os.ErrDeadlineExceeded:
637 return nil
638 }
639 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
640
641 third:
642 if isPlatformError(nestedErr) {
643 return nil
644 }
645 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
646 }
647
648 func TestAcceptError(t *testing.T) {
649 handler := func(ls *localServer, ln Listener) {
650 for {
651 ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond))
652 c, err := ln.Accept()
653 if perr := parseAcceptError(err); perr != nil {
654 t.Error(perr)
655 }
656 if err != nil {
657 if c != nil {
658 t.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c, c)
659 }
660 if nerr, ok := err.(Error); !ok || (!nerr.Timeout() && !nerr.Temporary()) {
661 return
662 }
663 continue
664 }
665 c.Close()
666 }
667 }
668 ls, err := newLocalServer("tcp")
669 if err != nil {
670 t.Fatal(err)
671 }
672 if err := ls.buildup(handler); err != nil {
673 ls.teardown()
674 t.Fatal(err)
675 }
676
677 time.Sleep(100 * time.Millisecond)
678 ls.teardown()
679 }
680
681
682
683
684 func parseCommonError(nestedErr error) error {
685 if nestedErr == nil {
686 return nil
687 }
688
689 switch err := nestedErr.(type) {
690 case *OpError:
691 if err := err.isValid(); err != nil {
692 return err
693 }
694 nestedErr = err.Err
695 goto second
696 }
697 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
698
699 second:
700 if isPlatformError(nestedErr) {
701 return nil
702 }
703 switch err := nestedErr.(type) {
704 case *os.SyscallError:
705 nestedErr = err.Err
706 goto third
707 case *os.LinkError:
708 nestedErr = err.Err
709 goto third
710 case *fs.PathError:
711 nestedErr = err.Err
712 goto third
713 }
714 switch nestedErr {
715 case ErrClosed:
716 return nil
717 }
718 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
719
720 third:
721 if isPlatformError(nestedErr) {
722 return nil
723 }
724 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
725 }
726
727 func TestFileError(t *testing.T) {
728 switch runtime.GOOS {
729 case "windows":
730 t.Skipf("not supported on %s", runtime.GOOS)
731 }
732
733 f, err := os.CreateTemp("", "go-nettest")
734 if err != nil {
735 t.Fatal(err)
736 }
737 defer os.Remove(f.Name())
738 defer f.Close()
739
740 c, err := FileConn(f)
741 if err != nil {
742 if c != nil {
743 t.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c, c)
744 }
745 if perr := parseCommonError(err); perr != nil {
746 t.Error(perr)
747 }
748 } else {
749 c.Close()
750 t.Error("should fail")
751 }
752 ln, err := FileListener(f)
753 if err != nil {
754 if ln != nil {
755 t.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln, ln)
756 }
757 if perr := parseCommonError(err); perr != nil {
758 t.Error(perr)
759 }
760 } else {
761 ln.Close()
762 t.Error("should fail")
763 }
764 pc, err := FilePacketConn(f)
765 if err != nil {
766 if pc != nil {
767 t.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc, pc)
768 }
769 if perr := parseCommonError(err); perr != nil {
770 t.Error(perr)
771 }
772 } else {
773 pc.Close()
774 t.Error("should fail")
775 }
776
777 ln, err = newLocalListener("tcp")
778 if err != nil {
779 t.Fatal(err)
780 }
781
782 for i := 0; i < 3; i++ {
783 f, err := ln.(*TCPListener).File()
784 if err != nil {
785 if perr := parseCommonError(err); perr != nil {
786 t.Error(perr)
787 }
788 } else {
789 f.Close()
790 }
791 ln.Close()
792 }
793 }
794
795 func parseLookupPortError(nestedErr error) error {
796 if nestedErr == nil {
797 return nil
798 }
799
800 switch nestedErr.(type) {
801 case *AddrError, *DNSError:
802 return nil
803 case *fs.PathError:
804 return nil
805 }
806 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
807 }
808
View as plain text