hashicorp/terraform · error

provider : locked version selection doesn't match the…

Error message

provider %s: locked version selection %s doesn't match the updated version constraints %q

What it means

The locked version of a provider does not satisfy the configuration's version constraints, AND the current constraints differ from the constraints recorded in the lock file. This means the module author (or user) updated the version constraint in required_providers but did not run terraform init --upgrade to re-resolve. The lock file is stale relative to the changed requirement.

Solutions

  1. Run terraform init --upgrade to re-resolve providers against the updated constraints and refresh the lock file.
  2. If you intentionally want to keep the old version, revert the version constraint change in required_providers.
  3. After upgrading, commit the updated .terraform.lock.hcl to version control.
  4. Verify the new constraint is satisfiable: check the registry for available versions matching the constraint.

Example fix

# before — constraint changed but lock file not updated
required_providers {
  aws = { version = "~> 4.0" }  # was ~> 3.0, lock still says 3.x
}
terraform plan  # → error

# after — re-resolve
terraform init --upgrade
terraform plan
Defensive patterns

Strategy: validation

Validate before calling

// Verify lock file constraints match config constraints before plan
// Shell pre-check:
//   terraform init -lockfile=readonly  # fails if lock is stale
// If stale:
//   terraform init -upgrade

// Go-side check (embedding):
func verifyLockFreshness(workingDir string) error {
    cmd := exec.Command("terraform", "init", "-lockfile=readonly", "-input=false")
    cmd.Dir = workingDir
    return cmd.Run()
}

Prevention

When it happens

Trigger: A required_providers version constraint was changed (e.g., from ~> 3.0 to ~> 4.0) but terraform init was not run with --upgrade. The locked version satisfies the old constraint but not the new one, and the lock file still records the old constraint string.

Common situations: Team upgrades a provider major version in the config and pushes without re-running init. A module is updated upstream with tighter constraints. User edits required_providers locally to test a newer version but forgets to update the lock. Lock file and config are out of sync after a git merge or rebase.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/01d536550f940f41. Report an issue: GitHub.

Appendix: source

Thrown at internal/configs/config.go:312

			continue
		}

		selectedVersion := lock.Version()
		allowedVersions := providerreqs.MeetingConstraints(constraints)
		log.Printf("[TRACE] Config.VerifyDependencySelections: provider %s has %s to satisfy %q", providerAddr, selectedVersion.String(), providerreqs.VersionConstraintsString(constraints))
		if !allowedVersions.Has(selectedVersion) {
			// The most likely cause of this is that the author of a module
			// has changed its constraints, but this could also happen in
			// some other unusual situations, such as the user directly
			// editing the lock file to record something invalid. We'll
			// distinguish those cases here in order to avoid the more
			// specific error message potentially being a red herring in
			// the edge-cases.
			currentConstraints := providerreqs.VersionConstraintsString(constraints)
			lockedConstraints := providerreqs.VersionConstraintsString(lock.VersionConstraints())
			switch {
			case currentConstraints != lockedConstraints:
				errs = append(errs, fmt.Errorf("provider %s: locked version selection %s doesn't match the updated version constraints %q", providerAddr, selectedVersion.String(), currentConstraints))
			default:
				errs = append(errs, fmt.Errorf("provider %s: version constraints %q don't match the locked version selection %s", providerAddr, currentConstraints, selectedVersion.String()))
			}
		}
	}

	// Return multiple errors in an arbitrary-but-deterministic order.
	sort.Slice(errs, func(i, j int) bool {
		return errs[i].Error() < errs[j].Error()
	})

	return errs
}

// ProviderRequirements searches the full tree of modules under the receiver
// for both explicit and implicit dependencies on providers.
//
// The result is a full manifest of all of the providers that must be available

View on GitHub (pinned to d32a084675)