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

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

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.

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.

Appendix: 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)