# Getting an error with count meta argument

**URL:** <https://discuss.hashicorp.com/t/getting-an-error-with-count-meta-argument/67582>\
**Category:** Terraform\
**Created:** [June 5, 2024, 3:01pm UTC](https://discuss.hashicorp.com/t/getting-an-error-with-count-meta-argument/67582 "2024-06-05T15:01:51Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sanjoy1995](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/sanjoy1995/32/35448_2.png) [@Sanjoy1995](https://discuss.hashicorp.com/u/Sanjoy1995)\
**Post date:** [June 5, 2024, 3:01pm UTC](https://discuss.hashicorp.com/t/getting-an-error-with-count-meta-argument/67582/1 "2024-06-05T15:01:51Z")

</div>

resource “google\_sql\_database\_instance” “default” {  
count = 2  
project = var.project\_id  
name = var.name[count.index]  
}

resource “google\_sql\_user” “default” {  
name = “postgres”  
project = var.project\_id  
instance = google\_sql\_database\_instance.default[\*].name  
}

variable “name” {  
type = list(string)  
}

# tfavars

name = [“testdb1”, “testdb2”]

Getting an error google\_sql\_database\_instance.default is tuple with 2 elements.

Inappropriate value for attributeattribute instance : string required.

Is it possible to solve this with count & splat expression. Please help

---

<div class="post-metadata">

**Author:** ![ExtelligenceIT](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/extelligenceit/32/41411_2.png) [@ExtelligenceIT](https://discuss.hashicorp.com/u/ExtelligenceIT)\
**Post date:** [June 5, 2024, 3:57pm UTC](https://discuss.hashicorp.com/t/getting-an-error-with-count-meta-argument/67582/2 "2024-06-05T15:57:38Z")

</div>

Hi @Sanjoy1995,

As you have not said what you’re trying to achieve, but just looking at your code what I think you are attempting to do is:

1. deploy 2x `google_sql_database_instance` resources, named `testdb1` & `testdb2` based upon a list of names provided as an input variable. But this list could change/increase/decrease.
2. Have a user named “postgres” configured as a default user in each database instance provisioned.

Based upon this assumption:

1. No changes to your input variable - we will continue to work with a list of strings but we will make a small change to accommodate this when using a `for_each`

2. Consider changing your `google_sql_database_instance` to use a `for_each` rather than a `count`. The reason for this is explained briefly here: [When to Use `for_each` Instead of `count`](https://developer.hashicorp.com/terraform/language/meta-arguments/count#when-to-use-for_each-instead-of-count) but count is fragile and can cause unexpected destroy/recreate of resources when you add or remove an item from your list (except for the last element) or reorder the list:

```auto
resource “google_sql_database_instance” “default” {
  for_each = toset(var.name)
  project = var.project_id
  name = each.value
}

```

- _notes: `toset()` is used to convert the list to a set as `for_each` requires a map or a set._

1. We will now refactor your `google_sql_user` default user code as follows:

```auto
resource “google_sql_user” “default” {
  for_each = google_sql_database_instance.default
  name = “postgres”
  project = var.project_id
  instance = each.value.name
}

```

- _notes:_ This will iterate through all database instances created and add the user. The reference to `google_sql_database_instance.default` in the `for_each` sets an implicit dependency between the resources.

I have not been able to test the above in gcp (due to access or familiarity) but the example is idiomatic of the usage of for\_each instead of count to create multiple instances of the same resource based upon a list (or set or map) passed as a variable, and then creating further specific resources/sub-resources associated with each of them.

Hope that helps

Happy Terraforming

---

<div class="post-metadata">

**Author:** ![Sanjoy1995](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/sanjoy1995/32/35448_2.png) [@Sanjoy1995](https://discuss.hashicorp.com/u/Sanjoy1995)\
**Post date:** [June 5, 2024, 4:31pm UTC](https://discuss.hashicorp.com/t/getting-an-error-with-count-meta-argument/67582/4 "2024-06-05T16:31:24Z")

</div>

Hello @ExtelligenceIT ,

Thanks for your reply.

There is another resource where I’m using for\_each to create multiple database for each instance.

> resource “google\_sql\_database” “additional\_databases” {  
> for\_each = local.databases  
> project = var.project\_id  
> name = each.value.name  
> **instance = google\_sql\_database\_instance.default.name**  
> }

How do I reference the two instances in this setup?

I was trying to solve this problem using count & splat expression to avoid this kind of scenario.

---

<div class="post-metadata">

**Author:** ![ExtelligenceIT](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/extelligenceit/32/41411_2.png) [@ExtelligenceIT](https://discuss.hashicorp.com/u/ExtelligenceIT)\
**Post date:** [June 5, 2024, 4:51pm UTC](https://discuss.hashicorp.com/t/getting-an-error-with-count-meta-argument/67582/5 "2024-06-05T16:51:16Z")

</div>

So, as my recommendation in the above example was to use a `for_each` you will now have two `google_sql_database_instance.default` instances that have the keys `testdb1` & `testdb2`

My assumption based upon what you’ve provided is that you want to associate each of databases created with the `google_sql_database` with a specific instance (as opposed to creating all of the “additional databases” against all instances (but if this is incorrect then please clarify)

To reference the `name` attribute for the instances now they are part of a for\_each it takes the form: `google_sql_database_instance.default["testdb1"].name`

Assuming your `local.databases` is a map it may look like this:

```auto
locals {
  databases = {
    db100 = { # <-- a database to be deployed to instance testdb1
      name = "nameofdb100"
      instance = "testdb1"
    }
    db200 = { # <-- a database to be deployed to instance testdb2
      name = "nameofdb200"
      instance = "testdb2"
    }
  }
   db45 = { # <-- another database to be deployed to instance testdb2
      name = "nameofdb45"
      instance = "testdb2"
    }
}

```

And therefore your code would be updated along these lines:

```auto
resource “google_sql_database” “additional_databases” {
    for_each = local.databases
    project = var.project_id
    name = each.value.name
    instance = google_sql_database_instance.default[each.value.instance].name
}

```

This is iterating through your local.databases map. Using the value of the name value of each map item for the `name` of the `google_sql_database` instance, and the instance value of the map item for the `instance`

These new database resources will use the key from local.database and thus would be able to be referenced as:

```auto
google_sql_database.additional_databases["db100 "]
google_sql_database.additional_databases["db200 "]
google_sql_database.additional_databases["db45"]

```

Again, I have not been able to test the above against gcp, but the examples are straightforward and typical.

---

<div class="post-metadata">

**Author:** ![Sanjoy1995](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/sanjoy1995/32/35448_2.png) [@Sanjoy1995](https://discuss.hashicorp.com/u/Sanjoy1995)\
**Post date:** [June 5, 2024, 5:04pm UTC](https://discuss.hashicorp.com/t/getting-an-error-with-count-meta-argument/67582/6 "2024-06-05T17:04:23Z")

</div>

Hello @ExtelligenceIT ,

Thank you for your help. I will test it as per your suggestion and let you know.

However, is it possible to solve it using count & splat.

For the instance name variable, I’m using type=list(string). I’m confused from where it’s getting tuple.

Error message when giving ref

> instance = google\_sql\_database\_instance.default[\*].name

google\_sql\_database\_instance.default is tuple with 2 elements.

Inappropriate value for attributeattribute instance : string required.

---

<div class="post-metadata">

**Author:** ![ExtelligenceIT](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/extelligenceit/32/41411_2.png) [@ExtelligenceIT](https://discuss.hashicorp.com/u/ExtelligenceIT)\
**Post date:** [June 6, 2024, 10:18am UTC](https://discuss.hashicorp.com/t/getting-an-error-with-count-meta-argument/67582/7 "2024-06-06T10:18:21Z")

</div>

Hi @Sanjoy1995

`google_sql_database_instance.default[*].name` is a tuple

> [@Sanjoy1995](#):
>
> Error message when giving ref
> 
> > instance = google\_sql\_database\_instance.default[\*].name \<— TUPLE
> 
> google\_sql\_database\_instance.default is tuple with 2 elements.

Given the below (to simulate:

```auto
locals {
    name = ["testdb1", "testdb2"]
}

```

Then `local.name[*]` is equivalent to `local.name`:

```auto
PS C:\Development\discuss\67582> terraform console
> local.name[*]
[
  "testdb1",
  "testdb2",
]
> type(local.name[*])
tuple([
    string,
    string,
])
> type(local.name)
tuple([
    string,
    string,
])
> local.name
[
  "testdb1",
  "testdb2",
]

```

Remember that you need to create each database as a resource. Just because you have a database of the same name across different database\_instances does not mean that they are the same database (They are different databases with the same name.)

Therefore the for\_each is required to create the multiple database instances, and a database can only belong to one database\_instance.

Using a splat in the instance reference is the same as saying ‘associate this database to all of the database instances contained in the tuple’ which you can’t do due to a database only being able to be associated to one instance.

## Extending this example

If the requirement is to create the same named databases in the list for each database instance then you will need to create a new map containing every combination of database x instance:

| | instance A | instance B |
| --- | --- | --- |
| **db 1** | A1 | B1 |
| **db 2** | A2 | B2 |

Therefore you would create 4x database resources (A1,B1,A2,B2)

The below code has two lists and creates a `local` which contains maps of the above. It then creates a `terraform_data` resource (to simulate the database resource) for each combination via a `for_each` against `local.combinations`

```auto
locals {
  instances = ["instance_a", "instance_b"]
  databases = ["db_1", "db_2"]

  # create a cartesian product of instances and databases as maps with a composite key
  combinations = merge([
    for instance in local.instances : {
      for database in local.databases : "${instance}-${database}" => {
        instance = instance
        database = database
      }
    }
  ]...)
}

# create a data resource for each combination (Simulates the database resource)
resource "terraform_data" "databases" {
  for_each = local.combinations
  input = {
    instance = each.value.instance
    databases_name = each.value.database
  }

}

output "combinations" {
  value = local.combinations
}

```

Place this code into a main.tf in an empty directory and run terraform plan/apply to see the outcome and to experiment.

HTH

Happy Terraforming

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/hashicorp/original/1X/79bf76adfd92a75631996933098f9ce29d37abf3.svg) [@system](https://discuss.hashicorp.com/u/system)\
**Post date:** [December 3, 2024, 10:18am UTC](https://discuss.hashicorp.com/t/getting-an-error-with-count-meta-argument/67582/8 "2024-12-03T10:18:25Z")

</div>

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.
