Summary
Terraform v1.15.0 enforces stricter evaluation of validation blocks inside variable
declarations. When a validation condition references another variable (var.Y
inside the validation of variable "X"), and the referenced variable has not been
processed yet (for example, during terraform test with targeted operations or partial
graph evaluation), Terraform now errors:
Error: Reference to uninitialized variable
The variable var.<name> was not processed by the most recent operation,
this likely means the previous operation either failed or was incomplete due to targeting.
This was previously tolerated. Local apply with Terraform v1.14.x passes, but any
operation under v1.15+ that initializes a working directory containing these
cross-variable validations fails. There are 10 cross-variable validation blocks across
5 components that need to migrate from variable.validation to
lifecycle.precondition on a root-level guard resource.
Problem
Cross-variable validation (var.Y referenced inside variable "X") is no longer safe
under Terraform v1.15. Preconditions are evaluated during plan with all variables fully
resolved, so they are unaffected by the v1.15 strictness on validation blocks.
Affected Locations (current as of main, 2026-06-11)
variables.deps.tf cross-variable validations
variables.tf cross-variable validations
Proposed Solution
Migrate each cross-variable validation into a lifecycle.precondition block on a
terraform_data "validation guard" resource at the root of each module. Preconditions
are evaluated during plan with all variables fully resolved.
Before (in variables.deps.tf)
variable "ml_workload_identity" {
type = object({
id = string
principal_id = string
})
description = "AzureML workload managed identity object containing id and principal_id."
default = null
validation {
condition = (!var.should_assign_ml_workload_identity_roles) || (var.ml_workload_identity != null)
error_message = "ml_workload_identity must be provided when should_assign_ml_workload_identity_roles is true."
}
}
After (validation removed from the variable)
variable "ml_workload_identity" {
type = object({
id = string
principal_id = string
})
description = "AzureML workload managed identity object containing id and principal_id."
default = null
}
Added in main.tf (single guard resource per component)
resource "terraform_data" "validate_inputs" {
lifecycle {
precondition {
condition = !var.should_assign_ml_workload_identity_roles || var.ml_workload_identity != null
error_message = "ml_workload_identity must be provided when should_assign_ml_workload_identity_roles is true."
}
precondition {
condition = !var.should_associate_network_security_group || var.network_security_group != null
error_message = "network_security_group must be provided when should_associate_network_security_group is true."
}
precondition {
condition = !var.should_enable_nat_gateway || var.nat_gateway != null
error_message = "nat_gateway must be provided when should_enable_nat_gateway is true."
}
}
}
For multi-condition rules (for example, arc_onboarding_identity mutual exclusion),
translate each validation block to a separate precondition block on the same
terraform_data resource, preserving the original error messages verbatim.
Per-component edits
src/000-cloud/080-azureml/terraform/ — Remove three validation blocks from
variables.deps.tf (ml_workload_identity, network_security_group, nat_gateway).
Add terraform_data "validate_inputs" to main.tf with three preconditions.
src/100-edge/100-cncf-cluster/terraform/ — Remove two validation blocks on
arc_onboarding_identity and one on key_vault from variables.deps.tf; remove the
validation block on should_generate_cluster_server_token from variables.tf. Add
terraform_data "validate_inputs" to main.tf with four preconditions (arc identity
required, arc identity mutual exclusion, key vault required, cluster_server_token vs
should_generate_cluster_server_token).
src/100-edge/100-cncf-cluster/terraform/modules/ubuntu-k3s/ — Remove the
validation block on should_generate_cluster_server_token from variables.tf. Add a
precondition (on a new terraform_data or an existing root-level resource in the
module's main.tf) enforcing the same rule.
src/000-cloud/036-managed-redis/terraform/ — Remove the validation block on
private_endpoint_subnet from variables.deps.tf. Add terraform_data "validate_inputs" to main.tf with a precondition.
src/000-cloud/031-fabric/terraform/ — Remove the validation block on
fabric_capacity_admins from variables.tf. Add terraform_data "validate_inputs" to
main.tf with a precondition.
Implementation notes
- Preserve original error messages verbatim so downstream documentation and operator
tooling continues to match.
- Prefer
terraform_data "validate_inputs" over null_resource: it is built-in (no extra
provider) and idempotent across plans.
- If a component's
main.tf already contains a sentinel/guard resource with
lifecycle.precondition, append the new preconditions there instead of introducing a new
terraform_data resource.
Suggested approach: HVE Core RPI workflow
Contributors can use the HVE Core Research → Plan → Implement → Review (RPI) workflow
to let GitHub Copilot AI assist with this change while keeping every decision traceable. See
Understanding the RPI Workflow.
This change qualifies for RPI: it spans multiple files (5 components) and crosses concerns
across variables.tf, variables.deps.tf, and main.tf.
- Research —
/task-research migrate cross-variable terraform validations to lifecycle.precondition.
Capture the exact current locations (table in this issue, ), the v1.15 error class, and the
terraform_data "validate_inputs" pattern with evidence and line numbers.
/clear
- Plan —
/task-plan. Produce a per-component task list with checkboxes covering the
10 validation migrations and the preconditions to add to each main.tf.
/clear
- Implement —
/task-implement. Execute the plan component by component, tracking
changes in the changes log.
/clear
- Review —
/task-review. Validate against the plan, run lint/validate, and confirm
intentional misconfigurations still fail at plan time with identical error messages.
Remember to /clear between phases and open the relevant .copilot-tracking/ artifact
before invoking the next agent.
Validation
For each affected component:
- Run
npm run tf-validate -- <component-path> and confirm clean validation.
- Run
npm run tflint-fix -- <component-path> to ensure lint cleanliness.
- Run
terraform test (or npm run tf-test -- <component-path>) under Terraform v1.15+
to confirm the original error class no longer occurs.
- Spot-check that intentional misconfigurations (for example,
should_assign_ml_workload_identity_roles = true with ml_workload_identity = null)
still fail at plan time with the same error messages.
- Run
npm run tf-docs (or the Terraform Build task) to regenerate each component's
auto-generated README.md. The new terraform_data "validate_inputs" resource appears
in the generated Resources section, so the docs must be regenerated and committed.
Acceptance criteria
Note: ADO pipeline Terraform version (manual, secondary)
The ADO pipeline template still uses terraformVersion: latest, which resolves to v1.15+
and surfaces this error before the migration lands:
ADO pipelines are secondary (GitHub Actions is the primary CI, and those workflows were
already pinned to 1.12.2 via #484). A long-term fix is not required here. As a manual
stopgap until this migration merges, pin the ADO template to a v1.14.x version, for example:
Revert to latest (or bump deliberately) once the precondition migration is verified under
v1.15+.
Summary
Terraform v1.15.0 enforces stricter evaluation of
validationblocks insidevariabledeclarations. When a validation
conditionreferences another variable (var.Yinside the validation of
variable "X"), and the referenced variable has not beenprocessed yet (for example, during
terraform testwith targeted operations or partialgraph evaluation), Terraform now errors:
This was previously tolerated. Local apply with Terraform v1.14.x passes, but any
operation under v1.15+ that initializes a working directory containing these
cross-variable validations fails. There are 10 cross-variable validation blocks across
5 components that need to migrate from
variable.validationtolifecycle.preconditionon a root-level guard resource.Problem
Cross-variable validation (
var.Yreferenced insidevariable "X") is no longer safeunder Terraform v1.15. Preconditions are evaluated during plan with all variables fully
resolved, so they are unaffected by the v1.15 strictness on
validationblocks.Affected Locations (current as of
main, 2026-06-11)variables.deps.tfcross-variable validationsvalidationlineml_workload_identityvar.should_assign_ml_workload_identity_rolesnetwork_security_groupvar.should_associate_network_security_groupnat_gatewayvar.should_enable_nat_gatewayarc_onboarding_identity(validation 1)var.should_assign_roles,var.arc_onboarding_sp,var.arc_onboarding_principal_idsarc_onboarding_identity(validation 2)var.should_assign_roles,var.arc_onboarding_sp,var.arc_onboarding_principal_idskey_vaultvar.should_upload_to_key_vaultprivate_endpoint_subnetvar.should_enable_private_endpointvariables.tfcross-variable validationsvalidationlinefabric_capacity_adminsvar.should_create_fabric_capacityshould_generate_cluster_server_tokenvar.cluster_server_tokenshould_generate_cluster_server_tokenvar.cluster_server_tokenProposed Solution
Migrate each cross-variable validation into a
lifecycle.preconditionblock on aterraform_data"validation guard" resource at the root of each module. Preconditionsare evaluated during plan with all variables fully resolved.
Before (in
variables.deps.tf)After (validation removed from the variable)
Added in
main.tf(single guard resource per component)For multi-condition rules (for example,
arc_onboarding_identitymutual exclusion),translate each
validationblock to a separatepreconditionblock on the sameterraform_dataresource, preserving the original error messages verbatim.Per-component edits
src/000-cloud/080-azureml/terraform/— Remove threevalidationblocks fromvariables.deps.tf(ml_workload_identity,network_security_group,nat_gateway).Add
terraform_data "validate_inputs"tomain.tfwith three preconditions.src/100-edge/100-cncf-cluster/terraform/— Remove twovalidationblocks onarc_onboarding_identityand one onkey_vaultfromvariables.deps.tf; remove thevalidationblock onshould_generate_cluster_server_tokenfromvariables.tf. Addterraform_data "validate_inputs"tomain.tfwith four preconditions (arc identityrequired, arc identity mutual exclusion, key vault required, cluster_server_token vs
should_generate_cluster_server_token).
src/100-edge/100-cncf-cluster/terraform/modules/ubuntu-k3s/— Remove thevalidationblock onshould_generate_cluster_server_tokenfromvariables.tf. Add aprecondition (on a new
terraform_dataor an existing root-level resource in themodule's
main.tf) enforcing the same rule.src/000-cloud/036-managed-redis/terraform/— Remove thevalidationblock onprivate_endpoint_subnetfromvariables.deps.tf. Addterraform_data "validate_inputs"tomain.tfwith a precondition.src/000-cloud/031-fabric/terraform/— Remove thevalidationblock onfabric_capacity_adminsfromvariables.tf. Addterraform_data "validate_inputs"tomain.tfwith a precondition.Implementation notes
tooling continues to match.
terraform_data "validate_inputs"overnull_resource: it is built-in (no extraprovider) and idempotent across plans.
main.tfalready contains a sentinel/guard resource withlifecycle.precondition, append the new preconditions there instead of introducing a newterraform_dataresource.Suggested approach: HVE Core RPI workflow
Contributors can use the HVE Core Research → Plan → Implement → Review (RPI) workflow
to let GitHub Copilot AI assist with this change while keeping every decision traceable. See
Understanding the RPI Workflow.
This change qualifies for RPI: it spans multiple files (5 components) and crosses concerns
across
variables.tf,variables.deps.tf, andmain.tf./task-research migrate cross-variable terraform validations to lifecycle.precondition.Capture the exact current locations (table in this issue, ), the v1.15 error class, and the
terraform_data "validate_inputs"pattern with evidence and line numbers./clear/task-plan. Produce a per-component task list with checkboxes covering the10 validation migrations and the preconditions to add to each
main.tf./clear/task-implement. Execute the plan component by component, trackingchanges in the changes log.
/clear/task-review. Validate against the plan, run lint/validate, and confirmintentional misconfigurations still fail at plan time with identical error messages.
Remember to
/clearbetween phases and open the relevant.copilot-tracking/artifactbefore invoking the next agent.
Validation
For each affected component:
npm run tf-validate -- <component-path>and confirm clean validation.npm run tflint-fix -- <component-path>to ensure lint cleanliness.terraform test(ornpm run tf-test -- <component-path>) under Terraform v1.15+to confirm the original error class no longer occurs.
should_assign_ml_workload_identity_roles = truewithml_workload_identity = null)still fail at plan time with the same error messages.
npm run tf-docs(or the Terraform Build task) to regenerate each component'sauto-generated
README.md. The newterraform_data "validate_inputs"resource appearsin the generated Resources section, so the docs must be regenerated and committed.
Acceptance criteria
validationblocks removed from the variables above.terraform_data "validate_inputs"(or appended preconditions on anexisting guard) added to each of the 5 affected components/modules.
npm run tf-validateandnpm run tflint-fix-allpass with zero errors.npm run tf-docsregenerated and committed for each affected component.Note: ADO pipeline Terraform version (manual, secondary)
The ADO pipeline template still uses
terraformVersion: latest, which resolves to v1.15+and surfaces this error before the migration lands:
terraformVersion: latestADO pipelines are secondary (GitHub Actions is the primary CI, and those workflows were
already pinned to
1.12.2via #484). A long-term fix is not required here. As a manualstopgap until this migration merges, pin the ADO template to a v1.14.x version, for example:
Revert to
latest(or bump deliberately) once the precondition migration is verified underv1.15+.