From ba6401883844229579c3d9cfc337381ab61a300a Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 20 Apr 2026 17:00:22 -0600 Subject: [PATCH] fix(httpcache): propagate sidecar write errors from Fetch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit saveMeta now returns an error instead of silently swallowing WriteFile/ Rename failures. Fetch wraps and returns it (with updated=true, since the body rename already succeeded). Callers get a loud signal when the sidecar can't be written — the body is still good, but the next conditional GET may redownload. --- net/httpcache/httpcache.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/net/httpcache/httpcache.go b/net/httpcache/httpcache.go index 0f218e5..93ae6a5 100644 --- a/net/httpcache/httpcache.go +++ b/net/httpcache/httpcache.go @@ -89,17 +89,21 @@ func (c *Cacher) loadMeta() { } // saveMeta writes etag/lastMod to the sidecar file atomically. -func (c *Cacher) saveMeta() { +func (c *Cacher) saveMeta() error { m := cacheMeta{ETag: c.etag, LastMod: c.lastMod} data, err := json.Marshal(m) if err != nil { - return + return err } tmp := c.metaPath() + ".tmp" if err := os.WriteFile(tmp, data, 0o644); err != nil { - return + return err } - os.Rename(tmp, c.metaPath()) + if err := os.Rename(tmp, c.metaPath()); err != nil { + _ = os.Remove(tmp) + return err + } + return nil } // New creates a Cacher that fetches URL and writes it to path. @@ -219,7 +223,9 @@ func (c *Cacher) Fetch() (updated bool, err error) { if lm := resp.Header.Get("Last-Modified"); lm != "" { c.lastMod = lm } - c.saveMeta() + if err := c.saveMeta(); err != nil { + return true, fmt.Errorf("save meta for %s: %w", c.Path, err) + } return true, nil }