{"record":{"id":"f5e3a7efa68c9b62","repo":"hashicorp/terraform","slug":"tag-object-values-must-be-strings","errorCode":null,"errorMessage":"tag object values must be strings","messagePattern":"tag object values must be strings","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cloud/backend.go","lineNumber":508,"sourceCode":"\t\tret.token = val.AsString()\n\t\tlog.Printf(\"[TRACE] cloud: found token in cloud config block\")\n\t}\n\n\t// Grab any workspace/project info from the nested config object in one go,\n\t// so it's easier to work with.\n\tvar name, project string\n\tif workspaces := obj.GetAttr(\"workspaces\"); !workspaces.IsNull() {\n\t\tif val := workspaces.GetAttr(\"name\"); !val.IsNull() {\n\t\t\tname = val.AsString()\n\t\t\tlog.Printf(\"[TRACE] cloud: found workspace name %q in cloud config block\", name)\n\t\t}\n\t\tif val := workspaces.GetAttr(\"tags\"); !val.IsNull() {\n\t\t\tlog.Printf(\"[TRACE] tags is a %q type\", val.Type().FriendlyName())\n\t\t\ttagsAsMap := make(map[string]string)\n\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 != \"\" {","sourceCodeStart":490,"sourceCodeEnd":526,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/cloud/backend.go#L490-L526","documentation":"Returned by the cloud backend config parser (cloud/backend.go:508) when the `workspaces.tags` attribute is an object or map type but one of its values is not a string. The parser builds a map[string]string; if any value's cty type is not cty.String it appends this error and returns immediately, rejecting the backend configuration.","triggerScenarios":"A cloud backend block with `workspaces { tags = { Env = 1 } }` (number value) or `{ Flag = true }` (bool value) — val.Type() != cty.String for that value at cloud/backend.go:508.","commonSituations":"Using a number/bool/list as a tag value instead of a string. Forgetting to wrap a tag value in quotes.","solutions":["Make every value in the tags object a string literal, e.g. `{ Env = \"prod\" }`.","If values come from variables, type them as string(string) or string-map (map(string))."],"exampleFix":"# before\nworkspaces {\n  tags = { Env = 1, Region = \"us\" }\n}\n# after\nworkspaces {\n  tags = { Env = \"1\", Region = \"us\" }\n}","handlingStrategy":"type-guard","validationCode":"// Ensure every tag value is a string before writing the backend block.\nfunc tagValuesAllStrings(m map[string]any) error {\n    for k, v := range m {\n        if _, ok := v.(string); !ok { return fmt.Errorf(\"tag object value for %q must be string\", k) }\n    }\n    return nil\n}","typeGuard":"func tagMapIsStringMap(v cty.Value) bool {\n    if !(v.Type().IsObjectType() || v.Type().IsMapType()) { return false }\n    for _, val := range v.AsValueMap() {\n        if val.Type() != cty.String { return false }\n    }\n    return true\n}","tryCatchPattern":null,"preventionTips":["Quote all tag values in the backend block.","Type tag variables as map(string).","Run terraform init/validate to surface parser errors early."],"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"}