hashicorp/vagrant · error · Vagrant::Errors::DownloadAlreadyInProgress
Download to global Vagrant location already in progress. Thi
Error message
Download to global Vagrant location already in progress. This
may be caused by other Vagrant processes attempting to download
a file to the same location.
Download path: %{dest_path}
Lock file path: %{lock_file_path} What it means
Errors::DownloadAlreadyInProgress wraps Errors::VagrantLocked from Util::FileMutex: the destination file in the global Vagrant box directory is already locked by another download. Vagrant serializes writes to ~/.vagrant.d via a '<dest>.lock' file, and contention aborts the second process.
Source
Thrown at lib/vagrant/action/builtin/box_add.rb:601
if File.file?(d.destination)
env[:ui].info(I18n.t("vagrant.actions.box.download.resuming"))
end
end
begin
mutex_path = d.destination + ".lock"
Util::FileMutex.new(mutex_path).with_lock do
begin
d.download!
rescue Errors::DownloaderInterrupted
# The downloader was interrupted, so just return, because that
# means we were interrupted as well.
@download_interrupted = true
env[:ui].info(I18n.t("vagrant.actions.box.download.interrupted"))
end
end
rescue Errors::VagrantLocked
raise Errors::DownloadAlreadyInProgress,
dest_path: d.destination,
lock_file_path: mutex_path
end
Pathname.new(d.destination)
end
# Tests whether the given URL points to a metadata file or a
# box file without completely downloading the file.
#
# @param [String] url
# @return [Boolean] true if metadata
def metadata_url?(url, env)
d = downloader(url, env, json: true, ui: false)
env[:hook].call(:authenticate_box_downloader, downloader: d)
# If we're downloading a file, cURL just returns no
# content-type (makes sense), so we just test if it is JSONView on GitHub (pinned to 35f3160f4a)
Solutions
- Wait for the other Vagrant process to finish, then retry the command.
- Identify the holder: lsof / ps aux | grep vagrant - if none, the lock is stale.
- Remove the stale lock file at the path printed in the error (e.g. rm /path/to/box.lock) once no process holds it.
- In CI, serialize box downloads or give each job an isolated VAGRANT_HOME.
Example fix
# before: two shells run simultaneously vagrant box add ubuntu/jammy64 # -> DownloadAlreadyInProgress (lock held by other process) # after: wait for first to finish, or if no vagrant runs: ps aux | grep '[v]agrant' || rm "$(vagrant box list >/dev/null; echo $HOME/.vagrant.d/boxes/... )" # simplest stale-lock cleanup (no vagrant processes running): find ~/.vagrant.d -name '*.lock' -delete
Defensive patterns
Strategy: retry
Validate before calling
lock = File.join(dest_dir, File.basename(dest) + ".lock") if File.exist?(lock) && !process_holds_lock?(lock) File.delete(lock) # clear stale lock before vagrant runs end
Type guard
def lock_free?(lock_path)
!File.exist?(lock_path) || `fuser #{lock_path} 2>/dev/null`.empty?
end Try / catch
attempts = 0
begin
env.cli("box", "add", name)
rescue Vagrant::Errors::DownloadAlreadyInProgress => e
attempts += 1
# e.extra_data[:dest_path], [:lock_file_path]
retry if attempts < 5 # other process usually finishes soon
raise
end Prevention
- Serialize box downloads in CI (one provision step) instead of racing parallel jobs.
- Set a per-job VAGRANT_HOME when jobs share a runner.
- After a hard kill of Vagrant, sweep stale *.lock files under ~/.vagrant.d before the next run.
When it happens
Trigger: Two vagrant box add / vagrant up (auto box download) processes race for the same box file; Util::FileMutex#with_lock on d.destination + '.lock' raises Errors::VagrantLocked, which is rescued and re-raised as DownloadAlreadyInProgress with dest_path and lock_file_path.
Common situations: Parallel CI jobs sharing a cached ~/.vagrant.d; running 'vagrant up' on multiple machines/projects simultaneously; a crashed previous run left a stale .lock file behind; concurrent plugin-driven downloads.
Related errors
- Vagrant attempted to acquire a lock named '%{name}', but thi
- Ignoring provider config for validation...
- This Vagrant environment has specified that it requires the
- A URL to a Vagrant Cloud server is not set, so boxes cannot
- The box '%{name}' could not be found or could not be accesse
AI-assisted analysis of hashicorp/vagrant@35f3160f4a (2026-08-21).
Data as JSON: /api/errors/758226b37c2f9d6a.
Report an issue: GitHub.