Problem
A Terraform plan for a google_storage_bucket_object resource indicates that the resource will be replaced. However, after you run terraform apply, the resource is destroyed but not recreated, and it no longer exists in Google Cloud Platform (GCP).
Your initial plan shows the resource replacement.
Terraform will perform the following actions:
# google_storage_bucket_object.example must be replaced
+/- resource "google_storage_bucket_object" "example" {
# ...
}The apply completes without error.
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
A subsequent plan shows that Terraform intends to create the resource again, confirming it does not exist in the state or in GCP.
Terraform will perform the following actions:
# google_storage_bucket_object.example will be created
+ resource "google_storage_bucket_object" "example" {
# ...
}Cause and Explanation
This issue occurs due to the interaction between the create_before_destroy lifecycle meta-argument and the behavior of the google_storage_bucket_object resource, where the name argument serves as the unique identifier in the Google Cloud Platform API.
When an attribute change forces a replacement, the plan shows that the name argument remains the same.
# google_storage_bucket_object.example must be replaced
+/- resource "google_storage_bucket_object" "example" {
# ...
name = "example_object"
# ...
~ source = "image.png" -> "image2.png" # forces replacement
}The create_before_destroy argument may be set directly on the resource.
resource "google_storage_bucket_object" "example" {
name = "example_object"
source = "image2.png"
bucket = google_storage_bucket.example.name
lifecycle {
create_before_destroy = true
}
}It may also be set on a resource that depends on google_storage_bucket_object.
resource "null_resource" "example" {
lifecycle {
create_before_destroy = true
}
depends_on = [google_storage_bucket_object.example]
}According to the create_before_destroydocumentation, dependent resources must enforce this behavior on the resources they depend on to avoid dependency cycles.
During the apply, Terraform first creates the new object. Because the name is unchanged, this action overwrites the existing object in GCP. Next, Terraform destroys the old object from the state. Because the identifier (name) is the same, the destroy operation targets the object that was just created, resulting in its deletion.
The apply logs show this sequence.
google_storage_bucket_object.example: Creating... google_storage_bucket_object.example: Creation complete after 0s [id=hashi_example_bucket-example_object] google_storage_bucket_object.example (deposed object f3bb18b6): Destroying... [id=hashi_example_bucket-example_object] google_storage_bucket_object.example: Destruction complete after 0s
This behavior can affect other provider resources that use a similar API design where a user-defined name acts as the unique identifier.
Solutions
There are two approaches to resolve this issue.
Solution 1: Change the name Argument During Replacement
When a resource update triggers create_before_destroy, ensure the name argument of the google_storage_bucket_object also changes. This provides a unique identifier for the new object, preventing the destroy operation from targeting it.
Solution 2: Avoid create_before_destroy
Alternatively, remove the create_before_destroy lifecycle rule from the google_storage_bucket_object resource and from any other resources that depend on it. This reverts to the default destroy-then-create behavior, which avoids the naming conflict.
Additional Information
For more details on this resource, refer to the official Google Provider documentation for google_storage_bucket_object.