From bfb9694f0c0f78c7b6c853d3ea3228b9e28b2f84 Mon Sep 17 00:00:00 2001 From: Alberto Bertogli Date: Sat, 3 Oct 2026 11:03:49 +0100 Subject: [PATCH] Wrap errors with %w when returning them Many places where we return errors don't use the %w wrapping, because they predate that functionality. This patch changes those to use %w, so callers can inspect the underlying errors with errors.Is and errors.As if needed in the future. The text of the errors does not change, and no existing callers inspect these errors, so there are no behaviour changes. --- internal/config/config.go | 10 +++++----- internal/courier/mda.go | 2 +- internal/courier/smtp.go | 14 +++++++------- internal/domaininfo/domaininfo.go | 2 +- internal/dovecot/dovecot.go | 10 +++++----- internal/queue/queue.go | 4 ++-- internal/sts/sts.go | 6 +++--- internal/userdb/userdb.go | 2 +- test/util/minidns/minidns.go | 4 ++-- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 2f3c067..4151000 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -44,13 +44,13 @@ func Load(path, overrides string) (*Config, error) { // Load from the path. buf, err := os.ReadFile(path) if err != nil { - return nil, fmt.Errorf("failed to read config at %q: %v", path, err) + return nil, fmt.Errorf("failed to read config at %q: %w", path, err) } fromFile := &Config{} err = prototext.Unmarshal(buf, fromFile) if err != nil { - return nil, fmt.Errorf("parsing config: %v", err) + return nil, fmt.Errorf("parsing config: %w", err) } override(c, fromFile) @@ -58,7 +58,7 @@ func Load(path, overrides string) (*Config, error) { fromOverrides := &Config{} err = prototext.Unmarshal([]byte(overrides), fromOverrides) if err != nil { - return nil, fmt.Errorf("parsing override: %v", err) + return nil, fmt.Errorf("parsing override: %w", err) } override(c, fromOverrides) @@ -67,14 +67,14 @@ func Load(path, overrides string) (*Config, error) { if c.Hostname == "" { c.Hostname, err = os.Hostname() if err != nil { - return nil, fmt.Errorf("could not get hostname: %v", err) + return nil, fmt.Errorf("could not get hostname: %w", err) } } // Validate the GiveUpSendAfter value. if _, err := time.ParseDuration(c.GiveUpSendAfter); err != nil { return nil, fmt.Errorf( - "invalid give_up_send_after value %q: %v", c.GiveUpSendAfter, err) + "invalid give_up_send_after value %q: %w", c.GiveUpSendAfter, err) } return c, nil diff --git a/internal/courier/mda.go b/internal/courier/mda.go index ea7ce6e..6898469 100644 --- a/internal/courier/mda.go +++ b/internal/courier/mda.go @@ -84,7 +84,7 @@ func (p *MDA) Deliver(from string, to string, data []byte) (error, bool) { permanent = status.ExitStatus() != 75 } } - err = tr.Errorf("MDA delivery failed: %v - %q", err, string(output)) + err = tr.Errorf("MDA delivery failed: %w - %q", err, string(output)) return err, permanent } diff --git a/internal/courier/smtp.go b/internal/courier/smtp.go index 6c68576..0af630a 100644 --- a/internal/courier/smtp.go +++ b/internal/courier/smtp.go @@ -160,18 +160,18 @@ func (a *attempt) deliver(mx string) (error, bool) { retry: conn, err := net.DialTimeout("tcp", mx+":"+*smtpPort, smtpDialTimeout) if err != nil { - return a.tr.Errorf("Could not dial: %v", err), false + return a.tr.Errorf("Could not dial: %w", err), false } defer conn.Close() conn.SetDeadline(time.Now().Add(smtpTotalTimeout)) c, err := smtp.NewClient(conn, mx) if err != nil { - return a.tr.Errorf("Error creating client: %v", err), false + return a.tr.Errorf("Error creating client: %w", err), false } if err = c.Hello(a.courier.HelloDomain); err != nil { - return a.tr.Errorf("Error saying hello: %v", err), false + return a.tr.Errorf("Error saying hello: %w", err), false } secLevel := domaininfo.SecLevel_PLAIN @@ -235,21 +235,21 @@ retry: } if err = c.MailAndRcpt(a.from, a.to); err != nil { - return a.tr.Errorf("MAIL+RCPT %v", err), smtp.IsPermanent(err) + return a.tr.Errorf("MAIL+RCPT %w", err), smtp.IsPermanent(err) } w, err := c.Data() if err != nil { - return a.tr.Errorf("DATA %v", err), smtp.IsPermanent(err) + return a.tr.Errorf("DATA %w", err), smtp.IsPermanent(err) } _, err = w.Write(a.data) if err != nil { - return a.tr.Errorf("DATA writing: %v", err), smtp.IsPermanent(err) + return a.tr.Errorf("DATA writing: %w", err), smtp.IsPermanent(err) } err = w.Close() if err != nil { - return a.tr.Errorf("DATA closing %v", err), smtp.IsPermanent(err) + return a.tr.Errorf("DATA closing %w", err), smtp.IsPermanent(err) } _ = c.Quit() diff --git a/internal/domaininfo/domaininfo.go b/internal/domaininfo/domaininfo.go index ae53d82..b206674 100644 --- a/internal/domaininfo/domaininfo.go +++ b/internal/domaininfo/domaininfo.go @@ -65,7 +65,7 @@ func (db *DB) Reload() error { _, err := db.store.Get(id, d) if err != nil { tr.Errorf("id %q: %v", id, err) - return fmt.Errorf("error loading %q: %v", id, err) + return fmt.Errorf("error loading %q: %w", id, err) } db.info[d.Name] = d diff --git a/internal/dovecot/dovecot.go b/internal/dovecot/dovecot.go index 38eb18d..cb42b11 100644 --- a/internal/dovecot/dovecot.go +++ b/internal/dovecot/dovecot.go @@ -119,11 +119,11 @@ func (a *Auth) Exists(user string) (bool, error) { // SPID\t err = expect(conn, "VERSION\t1") if err != nil { - return false, fmt.Errorf("error receiving version: %v", err) + return false, fmt.Errorf("error receiving version: %w", err) } err = expect(conn, "SPID\t") if err != nil { - return false, fmt.Errorf("error receiving SPID: %v", err) + return false, fmt.Errorf("error receiving SPID: %w", err) } // Send our version, and then the request. @@ -140,7 +140,7 @@ func (a *Auth) Exists(user string) (bool, error) { // Get the response, and we're done. resp, err := conn.ReadLine() if err != nil { - return false, fmt.Errorf("error receiving response: %v", err) + return false, fmt.Errorf("error receiving response: %w", err) } else if strings.HasPrefix(resp, "USER\t1\t") { return true, nil } else if strings.HasPrefix(resp, "NOTFOUND\t") { @@ -178,7 +178,7 @@ func (a *Auth) Authenticate(user, passwd string) (bool, error) { for { resp, err := conn.ReadLine() if err != nil { - return false, fmt.Errorf("error receiving handshake: %v", err) + return false, fmt.Errorf("error receiving handshake: %w", err) } if resp == "DONE" { break @@ -202,7 +202,7 @@ func (a *Auth) Authenticate(user, passwd string) (bool, error) { // Get the response, and we're done. resp, err = conn.ReadLine() if err != nil { - return false, fmt.Errorf("error receiving response: %v", err) + return false, fmt.Errorf("error receiving response: %w", err) } else if strings.HasPrefix(resp, "OK\t1") { return true, nil } else if strings.HasPrefix(resp, "FAIL\t1") { diff --git a/internal/queue/queue.go b/internal/queue/queue.go index cf168da..238cd2a 100644 --- a/internal/queue/queue.go +++ b/internal/queue/queue.go @@ -187,7 +187,7 @@ func (q *Queue) Put(tr *trace.Trace, from string, to []string, data []byte) (str rcpts, err := q.aliases.Resolve(tr, t) if err != nil { - return "", fmt.Errorf("error resolving aliases for %q: %v", t, err) + return "", fmt.Errorf("error resolving aliases for %q: %w", t, err) } // Add the recipients (after resolving aliases); this conversion is @@ -218,7 +218,7 @@ func (q *Queue) Put(tr *trace.Trace, from string, to []string, data []byte) (str err := item.WriteTo(q.path) if err != nil { - return "", tr.Errorf("failed to write item: %v", err) + return "", tr.Errorf("failed to write item: %w", err) } q.mu.Lock() diff --git a/internal/sts/sts.go b/internal/sts/sts.go index aaa4e0f..4b6f369 100644 --- a/internal/sts/sts.go +++ b/internal/sts/sts.go @@ -256,7 +256,7 @@ func httpGet(ctx context.Context, url string) ([]byte, error) { // https://tools.ietf.org/html/rfc8461#section-3.2 mt, _, err := mime.ParseMediaType(resp.Header.Get("Content-type")) if err != nil { - return nil, fmt.Errorf("HTTP media type error: %v", err) + return nil, fmt.Errorf("HTTP media type error: %w", err) } if mt != "text/plain" { return nil, ErrInvalidMediaType @@ -399,7 +399,7 @@ func (c *PolicyCache) load(domain string) (*Policy, error) { if err := p.Check(); err != nil { cacheInvalid.Add(1) return nil, fmt.Errorf( - "%s unmarshalled invalid policy %v: %v", domain, p, err) + "%s unmarshalled invalid policy %v: %w", domain, p, err) } return p, nil @@ -409,7 +409,7 @@ func (c *PolicyCache) store(domain string, p *Policy) error { data, err := json.Marshal(p) if err != nil { cacheMarshalErrors.Add(1) - return fmt.Errorf("%s failed to marshal policy %v, error: %v", + return fmt.Errorf("%s failed to marshal policy %v, error: %w", domain, p, err) } diff --git a/internal/userdb/userdb.go b/internal/userdb/userdb.go index 9dc4724..fe8c759 100644 --- a/internal/userdb/userdb.go +++ b/internal/userdb/userdb.go @@ -161,7 +161,7 @@ func (db *DB) AddUser(name, plainPassword string) error { s.Encrypted, err = scrypt.Key([]byte(plainPassword), s.Salt, 1<