Skip to content

fix(terraform): defer dynamic block expansion when for_each contains unknown values#33

Closed
blinkagent[bot] wants to merge 1 commit intomainfrom
fix/dynamic-block-wholly-known
Closed

fix(terraform): defer dynamic block expansion when for_each contains unknown values#33
blinkagent[bot] wants to merge 1 commit intomainfrom
fix/dynamic-block-wholly-known

Conversation

@blinkagent
Copy link

@blinkagent blinkagent bot commented Mar 9, 2026

Problem

Dynamic blocks with for_each referencing nested local values fail to expand correctly. When a local value references another local (e.g., local.ides contains local.vscode_name), the for_each value may be partially resolved on the first evaluation pass, containing cty.DynamicVal for the unresolved references.

The existing IsKnown() check only verifies the top-level value (a tuple/list), which appears "known" even when its nested elements contain DynamicVal. The dynamic block then expands with stale data and gets marked as expanded, preventing re-expansion on subsequent iterations when the context is fully resolved.

Reproduction

locals {
  vscode_name = "VSCode"
  ides = [{ name = local.vscode_name, value = "vscode" }]
}

data "coder_parameter" "ide_picker" {
  name    = "ide_picker"
  type    = "string"
  default = "vscode"
  dynamic "option" {
    for_each = local.ides
    content {
      name  = option.value.name   # evaluates to DynamicVal instead of "VSCode"
      value = option.value.value
    }
  }
}

Fix

Change the guard check in expandDynamic() from IsKnown() to IsWhollyKnown(), and return nil, nil (defer) instead of an error.

  • IsWhollyKnown() recursively checks all nested elements, catching DynamicVal inside tuples/objects
  • Returning nil, nil defers expansion without marking the block as expanded
  • On the next evaluation iteration, the locals are fully resolved and expansion succeeds

Testing

  • Verified with a test case in coder/preview that the nested local for_each now correctly resolves
  • All existing pkg/iac/terraform/... tests pass
  • All existing coder/preview non-E2E tests pass

Fixes coder/coder#20930

…unknown values

Change the guard check in expandDynamic() from IsKnown() to
IsWhollyKnown() so that dynamic blocks with partially-resolved
for_each values (containing cty.DynamicVal in nested elements)
are deferred instead of expanded with stale data.

Previously, a for_each value like:
  [{name: DynamicVal, value: "vscode"}]
would pass the IsKnown() check (the top-level tuple is known)
and expand the dynamic block with unresolved values. The block
would then be marked as expanded and never re-expanded, even
after subsequent evaluation passes resolve the nested locals.

IsWhollyKnown() recursively checks all nested elements, catching
the DynamicVal inside the tuple. Returning nil instead of an error
defers expansion without marking it as expanded, allowing the next
evaluation iteration to expand correctly once all locals resolve.

Fixes coder/coder#20930
@Emyrk Emyrk closed this Mar 9, 2026
@Emyrk Emyrk reopened this Mar 9, 2026
@Emyrk
Copy link
Member

Emyrk commented Mar 9, 2026

Fixed #37

@Emyrk Emyrk closed this Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Template parsing error with dynamic options that have interpolated values

1 participant