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
- Remove null entries from the impersonate_service_account_delegates list.
- If delegates come from a variable, filter them: use a local with [for d in var.delegates : d if d != null].
- 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
- Use Terraform locals to filter nulls: `locals { delegates = [for d in var.delegates : d if d != null] }`.
- Avoid templating delegate lists from sources that emit explicit nulls.
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
- Error decoding encryption key
- Error loading credentials
- Error loading encryption key
- Failed to delete state file
- Failed to open state file at
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)