Skip to content

emacs: refresh archives and retry when a package install fails - #30

Merged
tlockney merged 1 commit into
mainfrom
package-refresh-retry
Jul 28, 2026
Merged

emacs: refresh archives and retry when a package install fails#30
tlockney merged 1 commit into
mainfrom
package-refresh-retry

Conversation

@tlockney

Copy link
Copy Markdown
Owner

The failure

On m5air, adding magit produced:

⛔ Error (use-package): Failed to install magit:
   https://elpa.nongnu.org/nongnu/with-editor-3.4.9.tar: Not found

The cached archive index isn't wrong about which packages exist — it's wrong about their versions. GNU and nongnu ELPA keep only the current release of each package, so an index naming a superseded version resolves to a tarball the server has deleted. A 404, not a missing-package error.

Why nothing recovered

This is a regression from the startup work in #27. That change added:

(unless package-archive-contents
  (package-refresh-contents))

which refreshes only when the cache is empty — so after the first successful run on a machine, the index is never refreshed again and quietly rots.

use-package can't cover for it either. From use-package-ensure-elpa:

(if (assoc package package-archive-contents)
    (package-install package)      ; present: install, no refresh
  (package-refresh-contents)       ; absent: refresh, then install
  (package-install package))

magit was present in the stale cache, so it took the first branch and failed while resolving with-editor. Any newly added package hits this on any machine whose cache has aged; the only recovery was M-x package-refresh-contents by hand.

The fix

package-install now refreshes the archives and retries once on failure. It only runs on the error path, so a fresh cache costs nothing.

Verification

The advice was unit-tested across all three paths:

Case Expected Result
Install 404s once, then succeeds refresh, retry, succeed attempts=2 refreshed=t
Install fails persistently error still surfaces, not swallowed error surfaced after 2 attempts
Install succeeds first time no refresh, no network attempts=1 refreshed=nil

Full cold start against an empty init-directory: exit 0, no errors, 24 packages, magit-4.6.0 + with-editor-3.5.2.

What I could not reproduce end-to-end: I tried to recreate the exact 404 by corrupting a real cached nongnu index to name with-editor 3.5.999. package.el installed MELPA's date-versioned build (20260701.1252) instead, so it never hit nongnu's dead tarball — a difference in archive selection between that sandbox and m5air I did not chase further. The mechanism above is established by reading use-package-ensure-elpa and by the unit tests, not by a full reproduction.

Immediate unblock

On m5air, before this merges: M-x package-refresh-contents, then M-x package-install RET magit RET.

Installing magit on a machine whose archive cache was stale failed with
"https://elpa.nongnu.org/nongnu/with-editor-3.4.9.tar: Not found". The cache
is not wrong about which packages exist, it is wrong about their versions:
GNU and nongnu ELPA keep only the current release of each package, so an index
that names a superseded version resolves to a tarball the server has deleted.

Nothing in the config recovered from that. The refresh added earlier only runs
when package-archive-contents is empty, so after the first successful run on a
machine the index is never refreshed again. use-package cannot cover for it
either -- use-package-ensure-elpa refreshes only when the package is missing
from the cache:

    (if (assoc package package-archive-contents)
        (package-install package)      ; present: install, no refresh
      (package-refresh-contents)       ; absent: refresh, then install
      (package-install package))

magit was present in the stale cache, so it took the first branch and failed
resolving its dependency. Any newly added package hits this on any machine
whose cache has aged, and the only recovery was to run
M-x package-refresh-contents by hand.

package-install now refreshes and retries once on failure. That costs nothing
when the cache is fresh, since it only runs on the error path.
@tlockney
tlockney marked this pull request as ready for review July 28, 2026 05:42
@tlockney
tlockney merged commit c1a3a22 into main Jul 28, 2026
1 check passed
@tlockney
tlockney deleted the package-refresh-retry branch July 28, 2026 05:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant