{"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/c9def3e214014c1188faabfc4a5bde5095139765/internal/cloud/backend.go#L490-L526","documentation":"Config-parsing diagnostic from the cloud backend when workspaces.tags is an object/map type but one of its values is not a cty.String. All tag object values must be strings so they can be collected into a map[string]string.","triggerScenarios":"workspaces { tags = { Count = 3 } } — a numeric value in the tags object; or any value whose cty type is not cty.String.","commonSituations":"Passing a number/bool/list as a tag value; a variable typed as map(any) that contains non-string values.","solutions":["Ensure every tag value is a string, e.g. tags = { Count = \"3\" }.","Type the variable as map(string) so non-string values fail earlier."],"exampleFix":"// before\nworkspaces {\n  tags = {\n    Count = 3\n  }\n}\n// after\nworkspaces {\n  tags = {\n    Count = \"3\"\n  }\n}","handlingStrategy":"validation","validationCode":"# Type the tags variable as map(string) so non-string values fail early:\nvariable \"tags\" { type = map(string) }\n# Then: workspaces { tags = var.tags }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Type tag-object variables as map(string).","Convert numbers/bools to strings before assignment.","Run terraform validate in CI."],"tags":["terraform","cloud-backend","config-validation","hcl","tags"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}