{"record":{"id":"7d910d9ef84af5e7","repo":"hashicorp/terraform","slug":"tag-elements-must-be-strings","errorCode":null,"errorMessage":"tag elements must be strings","messagePattern":"tag elements must be strings","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cloud/backend.go","lineNumber":523,"sourceCode":"\t\t\tif val.Type().IsObjectType() || val.Type().IsMapType() {\n\t\t\t\tfor k, v := range val.AsValueMap() {\n\t\t\t\t\tif v.Type() != cty.String {\n\t\t\t\t\t\tdiags = diags.Append(errors.New(\"tag object values must be strings\"))\n\t\t\t\t\t\treturn ret, diags\n\t\t\t\t\t}\n\t\t\t\t\ttagsAsMap[k] = v.AsString()\n\t\t\t\t}\n\t\t\t\tlog.Printf(\"[TRACE] cloud: using tags %q from cloud config block\", tagsAsMap)\n\t\t\t\tret.workspaceMapping.TagsAsMap = tagsAsMap\n\t\t\t} else if val.Type().IsTupleType() || val.Type().IsSetType() {\n\t\t\t\tvar tagsAsSet []string\n\t\t\t\tlength := val.LengthInt()\n\t\t\t\tif length > 0 {\n\t\t\t\t\tit := val.ElementIterator()\n\t\t\t\t\tfor it.Next() {\n\t\t\t\t\t\t_, v := it.Element()\n\t\t\t\t\t\tif !v.Type().Equals(cty.String) {\n\t\t\t\t\t\t\tdiags = diags.Append(errors.New(\"tag elements must be strings\"))\n\t\t\t\t\t\t\treturn ret, diags\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif vs := v.AsString(); vs != \"\" {\n\t\t\t\t\t\t\ttagsAsSet = append(tagsAsSet, vs)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlog.Printf(\"[TRACE] cloud: using tags %q from cloud config block\", tagsAsSet)\n\t\t\t\tret.workspaceMapping.TagsAsSet = tagsAsSet\n\t\t\t} else {\n\t\t\t\tdiags = diags.Append(fmt.Errorf(\"tags must be a set or object, not %s\", val.Type().FriendlyName()))\n\t\t\t\treturn ret, diags\n\t\t\t}\n\t\t}\n\t\tif val := workspaces.GetAttr(\"project\"); !val.IsNull() {\n\t\t\tproject = val.AsString()\n\t\t\tlog.Printf(\"[TRACE] cloud: found project name %q in cloud config block\", project)","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/cloud/backend.go#L505-L541","documentation":"Returned by the cloud backend config parser (cloud/backend.go:523) when `workspaces.tags` is a tuple/set type but an element is not a string. The parser iterates element-by-element building []string; if `!v.Type().Equals(cty.String)` it appends this error and returns, rejecting the backend configuration.","triggerScenarios":"A cloud backend block with `workspaces { tags = [\"a\", 1, \"b\"] }` (mixed/non-string element) — the set/tuple branch at cloud/backend.go:514-524 hits a non-string element.","commonSituations":"Mixing numbers/bools into a list of tags. A variable typed as list(any) that yields non-string elements.","solutions":["Make every element of the tags list/set a string, e.g. `[\"a\", \"b\"]`.","Type the supplying variable as set(string) / list(string)."],"exampleFix":"# before\nworkspaces {\n  tags = [\"env:prod\", 9, \"region:us\"]\n}\n# after\nworkspaces {\n  tags = [\"env:prod\", \"region:us\"]\n}","handlingStrategy":"type-guard","validationCode":"func tagElementsAllStrings(v []any) error {\n    for _, e := range v {\n        if _, ok := e.(string); !ok { return errors.New(\"tag elements must be strings\") }\n    }\n    return nil\n}","typeGuard":"func tagSetAllString(v cty.Value) bool {\n    if !(v.Type().IsTupleType() || v.Type().IsSetType()) { return false }\n    it := v.ElementIterator()\n    for it.Next() {\n        _, el := it.Element()\n        if !el.Type().Equals(cty.String) { return false }\n    }\n    return true\n}","tryCatchPattern":null,"preventionTips":["Keep tags lists homogeneous strings.","Type tag variables as set(string)/list(string).","Avoid list(any) for tags."],"tags":["terraform","cloud-backend","tags","validation","config","types"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}