{"record":{"id":"61532852471baae4","repo":"kubernetes/kops","slug":"variable-q-is-both-an-array-and-a-scalar","errorCode":null,"errorMessage":"variable %q is both an array and a scalar","messagePattern":"variable %q is both an array and a scalar","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/terraformWriter/writer.go","lineNumber":202,"sourceCode":"\t\treturn fmt.Errorf(\"duplicate variable: %q\", key)\n\t}\n\tt.outputs[key] = v\n\n\treturn nil\n}\n\nfunc (t *TerraformWriter) AddOutputVariableArray(key string, literal *Literal) error {\n\tt.mutex.Lock()\n\tdefer t.mutex.Unlock()\n\n\tif t.outputs[key] == nil {\n\t\tv := &terraformOutputVariable{\n\t\t\tKey: key,\n\t\t}\n\t\tt.outputs[key] = v\n\t}\n\tif t.outputs[key].Value != nil {\n\t\treturn fmt.Errorf(\"variable %q is both an array and a scalar\", key)\n\t}\n\n\tt.outputs[key].ValueArray = append(t.outputs[key].ValueArray, literal)\n\n\treturn nil\n}\n\nfunc (t *TerraformWriter) GetDataSourcesByType() (map[string]map[string]interface{}, error) {\n\tdataSourcesByType := make(map[string]map[string]interface{})\n\n\tfor _, dataSource := range t.dataSources {\n\t\tdataSources := dataSourcesByType[dataSource.DataType]\n\t\tif dataSources == nil {\n\t\t\tdataSources = make(map[string]interface{})\n\t\t\tdataSourcesByType[dataSource.DataType] = dataSources\n\t\t}\n\n\t\ttfName := sanitizeName(dataSource.DataName)","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/terraformWriter/writer.go#L184-L220","documentation":"TerraformWriter.AddOutputVariableArray appends a literal to a Terraform output treated as an array. If the same key was already registered as a scalar output (Value != nil), the same output name would have to be both a scalar and an array, which Terraform cannot express, so kOps errors. It enforces one shape per output variable.","triggerScenarios":"A renderer calls AddOutputVariableArray(key, ...) for a key that another renderer previously registered via AddOutputVariable(key, scalar). The mixed registration happens when two different features emit outputs with the same name but different shapes.","commonSituations":"kOps internal naming collision between a scalar output and an array output with identical names; patched/extended kOps adding an array output over an existing scalar name; duplicated render logic registering both forms.","solutions":["Locate the renderer adding the scalar with the same key and rename/namespace one of the two outputs.","If patching kOps, choose a distinct key for the array output (e.g. key + \"_list\").","Check for duplicated resources in the cluster spec triggering both code paths.","Update kOps; shape collisions are internal bugs fixed upstream."],"exampleFix":"// before\nAddOutputVariable(\"vpc_id\", lit)\nAddOutputVariableArray(\"vpc_id\", lit2) // conflicts\n// after\nAddOutputVariable(\"vpc_id\", lit)\nAddOutputVariableArray(\"vpc_ids\", lit2)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := w.AddOutputVariableArray(key, lit); err != nil {\n    if strings.Contains(err.Error(), \"both an array and a scalar\") {\n        return fmt.Errorf(\"output %q shape conflict; rename array variant\", key)\n    }\n    return err\n}","preventionTips":["Never reuse an output key for both scalar and array values.","Use distinct suffixes (e.g. _list) for array outputs in custom code.","Report upstream collisions with the key from the message.","Avoid duplicate spec resources triggering both code paths."],"tags":["terraform","outputs","kops","internal"],"backgroundTag":"output-shape-conflict","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}