Terraform 1.3.7 repairs exact prerelease module selection
Terraform 1.3.7 fixes an inconsistency in module version constraints and a null-block panic in lifecycle processing.
An exact dependency constraint should behave the same with an explicit equals sign as it does without one. Terraform's module installer had an exception for prerelease versions. Its special filter compared the constraint's text with the candidate version's text, which made syntax significant where the intended meaning was identical. Terraform 1.3.7, released on January 4, fixes that mismatch. The release also prevents a panic when a null block returned by a provider reaches plan validation through ignore_changes.
These are small corrections to behavior that configuration authors already had reason to expect. I value Terraform because its reusable configuration language gives infrastructure APIs a common representation. That representation becomes less useful when apparently equivalent expressions produce different installation results. The prerelease fix makes the implementation agree with the documented dependency language.
Exact selection has a separate prerelease rule
Terraform's version constraint documentation at this release defines both = and an omitted operator as exact matches. Prerelease selection has a further restriction. A prerelease must be requested exactly, and ordinary range operators do not admit it. A constraint that compares versions therefore has more work to do than an ordinary numeric ordering check.
That restriction lets a module publisher expose an unfinished version without making it eligible for every consumer whose range would otherwise include it. A consumer has to choose the prerelease itself. The distinction matters even when the consumer supplies a range whose upper limit contains the prerelease suffix. The suffix in that comparison does not turn the range into an exact request.
The fix and its regression tests make this concrete. The exact-match fixture requests an existing acceptance-test module with the following syntax:
module "acctest_exact" {
source = "hashicorp/module-installer-acctest/aws"
version = "=0.0.3-alpha.1"
}
The test expects the installer to select 0.0.3-alpha.1. A separate fixture uses <=0.0.3-alpha.1 and expects the stable 0.0.2 release. Together the tests establish that the change admits the explicit exact request while preserving the exclusion of prereleases from ranges. The patch does not make prerelease selection generally more permissive.
Before the correction, the installer checked whether the candidate had a prerelease suffix and then compared two strings. A constraint containing an equals sign was not the same string as a version containing only its version number. That was enough to exclude a candidate before the ordinary constraint check could accept it. The error sat in the additional prerelease filter, which explains why fixing general version comparison alone would not have addressed it.
A limited parser change
Liam Cervante's implementation proposal introduces apparentlymart/go-versions into this filtering step. The provider installer already uses that library. Its constraint interpretation includes the exact-request rule that the module installer needs, so the patch uses its parsed constraint set to determine whether a prerelease is eligible.
The change does not replace every version operation in the module installer. After the additional filter accepts a candidate, the existing version logic still checks it. The patch also handles failures to parse either a constraint or a candidate under the second library. It logs the problem and skips that prerelease candidate. This keeps a registry's announcement of a prerelease from causing an unrelated consumer to receive a new user-facing error merely because the additional parser rejected something.
The review discusses this limited scope explicitly. Two libraries accepting version strings need not accept precisely the same inputs. Replacing an entire parser can therefore introduce compatibility questions beyond the original defect. Keeping the change within prerelease eligibility addresses the reported behavior while leaving the broader consolidation question open.
I prefer that scope for a patch release. Module and provider installation should agree about constraint meaning, but a correction to explicit prerelease requests does not need to become a redesign of all version handling. The paired exact and range tests document the intended distinction more clearly than a general claim of improved parsing could.
Null blocks can arrive through lifecycle handling
The other correction concerns a value that normal configuration decoding does not produce. In the null-block patch, the implementation comments explain that configuration cannot decode a nested block into a null value. A legacy provider can nevertheless return null, and ignore_changes can insert that value into the configuration used for plan validation.
Terraform's lifecycle documentation explains why values can take that route. Attributes named in ignore_changes participate in creation, but Terraform ignores their differences when planning updates. This allows another process to share responsibility for selected settings. Implementing that behavior requires Terraform to account for existing values when preparing the proposed change.
The validator compared the lengths of planned and configured list blocks. Asking a null list for its concrete length caused a panic. The fix substitutes an empty list of the correct element type for the null configuration value before comparing lengths. Its regression test supplies an empty prior list, a null configuration list, and an empty planned list, then expects validation to complete without error.
This normalization is local to validation. It does not mean that null and empty values become interchangeable throughout Terraform, and it does not change the documented purpose of ignore_changes. It handles a specific provider-originated representation at the point where the validator requires a list. For configurations affected by that combination, the practical result is that a normal planning operation can continue past a value the old validator could not process.