hashicorp/terraform · error

impersonate_service_account_delegates elements must not be…

Error message

impersonate_service_account_delegates elements must not be null

What it means

Thrown while building the service-account impersonation token source when the impersonate_service_account_delegates list contains a null element. The backend iterates the cty list and rejects any null entry before forwarding the delegates to impersonate.CredentialsTokenSource.

Solutions

  1. Remove null entries from the impersonate_service_account_delegates list.
  2. If delegates come from a variable, filter them: use a local with [for d in var.delegates : d if d != null].
  3. Leave impersonate_service_account_delegates unset entirely if you have no delegate chain.

Example fix

// before
backend "gcs" {
  bucket                       = "tf-state"
  impersonate_service_account  = "sa@proj.iam.gserviceaccount.com"
  impersonate_service_account_delegates = ["delegate@...", null]
}
// after
backend "gcs" {
  bucket                       = "tf-state"
  impersonate_service_account  = "sa@proj.iam.gserviceaccount.com"
  impersonate_service_account_delegates = ["delegate@..."]
}
Defensive patterns

Strategy: validation

Validate before calling

// Filter null delegates before passing to the backend config.
delegates := []string{}
for _, d := range rawDelegates {
    if d == nil || d == cty.NullVal(cty.String) { continue }
    delegates = append(delegates, d.AsString())
}

Type guard

func hasNullElement(listVal cty.Value) bool {
    if listVal.IsNull() || listVal.LengthInt() == 0 { return false }
    for it := listVal.ElementIterator(); it.Next(); {
        _, v := it.Element()
        if v.IsNull() { return true }
    }
    return false
}

Prevention

When it happens

Trigger: Configure is called with impersonate_service_account set AND impersonate_service_account_delegates as a non-empty list in which at least one element is cty.NullVal(cty.String).

Common situations: A templated backend block renders a delegate from a variable that is sometimes null; a list like ["acct@...", null] is built via compact() that failed to drop nulls; YAML-to-HCL conversion emits explicit nulls.

Related errors


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

Appendix: source

Thrown at internal/backend/remote-state/gcs/backend.go:223

			)
		}

		credOptions = append(credOptions, option.WithCredentialsJSON([]byte(contents)))
	}

	// Service Account Impersonation
	if v := data.String("impersonate_service_account"); v != "" {
		ServiceAccount := v
		var delegates []string

		delegatesVal := data.GetAttr("impersonate_service_account_delegates", cty.List(cty.String))
		if !delegatesVal.IsNull() && delegatesVal.LengthInt() != 0 {
			delegates = make([]string, 0, delegatesVal.LengthInt())
			for it := delegatesVal.ElementIterator(); it.Next(); {
				_, v := it.Element()
				if v.IsNull() {
					return backendbase.ErrorAsDiagnostics(
						fmt.Errorf("impersonate_service_account_delegates elements must not be null"),
					)
				}
				delegates = append(delegates, v.AsString())
			}
		}

		ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
			TargetPrincipal: ServiceAccount,
			Scopes:          []string{storage.ScopeReadWrite},
			Delegates:       delegates,
		}, credOptions...)

		if err != nil {
			return backendbase.ErrorAsDiagnostics(err)
		}

		opts = append(opts, option.WithTokenSource(ts))

View on GitHub (pinned to d32a084675)