hashicorp/vagrant · error · Vagrant::Errors::BoxAlreadyExists

The box you're attempting to add already exists. Remove it b

Error message

The box you're attempting to add already exists. Remove it before
adding it again or add it with the `--force` flag.

Name: %{name}
Provider: %{provider}
Version: %{version}

What it means

Errors::BoxAlreadyExists is raised during add_from_direct/add_from_metadata right before download: the box collection already contains the exact name+provider+version (and architecture) being added, and env[:box_force] (the --force flag) is not set.

Source

Thrown at lib/vagrant/action/builtin/box_add.rb:428

        # @return [Box]
        def box_add(urls, name, version, provider, md_url, env, **opts)
          display_architecture = opts[:architecture] == :auto ?
                                   Util::Platform.architecture : opts[:architecture]
          env[:ui].output(I18n.t(
            "vagrant.box_add_with_version",
            name: name,
            version: version,
            providers: [
              provider,
              display_architecture ? "(#{display_architecture})" : nil
            ].compact.join(" ")))

          # Verify the box we're adding doesn't already exist
          if provider && !env[:box_force]
            box = env[:box_collection].find(
              name, provider, version, opts[:architecture])
            if box
              raise Errors::BoxAlreadyExists,
                name: name,
                provider: provider,
                version: version
            end
          end

          # Now we have a URL, we have to download this URL.
          box = nil
          begin
            box_url = nil

            urls.each do |url|
              show_url = nil
              if url.is_a?(Array)
                show_url = url[1]
                url      = url[0]
              end

View on GitHub (pinned to 35f3160f4a)

Solutions

  1. Pass --force (env[:box_force]) to overwrite the existing box entry.
  2. Remove the existing box first ('vagrant box remove NAME --provider P --box-version V') if you want a clean slate.
  3. For updates, prefer 'vagrant box update' inside the project rather than re-adding.
  4. In scripts, guard with 'vagrant box list' (or collection.find) before adding.

Example fix

# before
vagrant box add hashicorp/bionic64   # already installed -> BoxAlreadyExists

# after
vagrant box add --force hashicorp/bionic64

# or remove then add
vagrant box remove hashicorp/bionic64 && vagrant box add hashicorp/bionic64
Defensive patterns

Strategy: validation

Validate before calling

# Same check BoxAdd performs, done by the caller
collection = env.box_collection
if collection.find(name, provider, version, architecture)
  # already present: force overwrite or skip
  env[:box_force] = true
end

Type guard

def box_installed?(collection, name, provider, version = nil, architecture = nil)
  !collection.find(name, provider, version, architecture).nil?
end

Try / catch

begin
  env.cli("box", "add", url)
rescue Vagrant::Errors::BoxAlreadyExists => e
  # e.extra_data[:name], [:provider], [:version]
  env.cli("box", "add", "--force", url)
end

Prevention

When it happens

Trigger: A provider for the box is determined and env[:box_force] is falsy; env[:box_collection].find(name, provider, version, opts[:architecture]) returns an existing box; the raise carries name, provider, version.

Common situations: Re-running a bootstrap script that calls 'vagrant box add' on every run; re-adding a box to update it (wrong mental model - add does not upgrade in place); CI caching a ~/.vagrant.d between jobs.

Related errors


AI-assisted analysis of hashicorp/vagrant@35f3160f4a (2026-08-21). Data as JSON: /api/errors/371e5fec64289edd. Report an issue: GitHub.