Skip to content

Upgrade issue from v2.0.1 to v3.0.0: not valid JSON for read_data and destroy_data #367

Description

@breml

Today I looked into upgrading Mastercard/restapi terraform provider from v2.0.1 to v.3.0.0 in our project. This failed with the following error message:

╷
│ Error: Invalid JSON String Value
│
│   with restapi_object.bootstrap-indices,
│   on resources-index.tf line 36, in resource "restapi_object" "bootstrap-indices":
│   36:   read_data   = ""
│
│ A string value was provided that is not valid JSON string format (RFC 7159).
│
│ Given Value:
│
╵
╷
│ Error: Invalid JSON String Value
│
│   with restapi_object.bootstrap-indices,
│   on resources-index.tf line 59, in resource "restapi_object" "bootstrap-indices":
│   59:   destroy_data   = ""
│
│ A string value was provided that is not valid JSON string format (RFC 7159).
│
│ Given Value:
│
╵

The use case we use this terraform provider for is related to bootstrap Elasticsearch indices, which get rotated automatically later on (by an Elasticsearch feature called index lifecycle policies). This is currently not supported by the official elasticstack terraform provider.
For this special use case we only care about creation and deletion of indices. In order to make read work, we read all the indices matching the respective pattern (using wild cards) and we ignore all the drift (ignore_all_server_changes = true). This worked flawlessly in the past (using v2.0.1 of the provider).

The config we used successfully with v2.0.1 looks like this:

locals {
  bootstrap_indices = toset([
    "some_index_name",
  ])
}

resource "restapi_object" "bootstrap-indices" {
  for_each = local.bootstrap_indices

  path = "/"
  data = jsonencode({
    aliases = {
      "${each.key}" = {
        is_write_index = true,
      },
    },
  })
  object_id                 = each.key
  ignore_all_server_changes = true
  debug                     = true

  read_method = "GET"
  read_path   = "/{id}-*"
  read_data   = ""

  create_method = "PUT"
  # encoded form of: /<{id}-{now/d}-000001>
  # {id} is replaced by the terraform provider, the rest is Elasticsearch date math:
  # https://www.elastic.co/docs/reference/elasticsearch/rest-apis/api-conventions
  create_path = "/%3C{id}-%7Bnow%2Fd%7D-000001%3E"

  # NOTE: This is just a placeholder operation, that is compatible with both
  # Elasticsearch and Mastercard/restapi Terraform provider.
  # We need this, since we do not want to perform any change in the case of
  # an update.
  update_method = "POST"
  update_path   = "/{id}/_validate/query"
  update_data = jsonencode({
    query = {}
  })

  # IMPORTANT: We use wildcards for delete, so all the indices for the given alias/prefix
  # are removed. This is necessary to allow destroy for index lifecycle policies (ILM),
  # since ILM are not deletable as long as they are still referenced by indices.
  destroy_method = "DELETE"
  destroy_path   = "/{id}-*"
  destroy_data   = ""

  lifecycle {
    prevent_destroy = true
  }
}

With the above configuration, the validation fails immediately, since "" is not considered valid JSON for read_data and update_data. So I tried several approaches like read_data = null, read_data = jsonencode(null), read_data = jsonencode({}). While these pass the validation of the config, terraform plan still fails. Based on the log files, it looks to me, that the reason for this is the current value in the terraform state, which is not valid json and therefore unmarshal for this value fails. This prevents the smooth migration from v2.0.1 to v3.0.0 for us.

Snippets from the debug logs with jsonencode({}) as value

2026-06-12T16:32:40.491+0200 [ERROR] provider.terraform-provider-restapi_v3.0.0: Response contains error diagnostic: tf_provider_addr=github.com/Mastercard/terraform-provider-restapi tf_rpc=ReadResource @caller=github.com/hashicorp/terraform-plugin-go@v0.29.0/tfprotov6/internal/diag/diagnostics.go:58 @module=sdk.proto diagnostic_attribute="AttributeName(\"destroy_data\")" diagnostic_summary="Invalid JSON String Value" tf_proto_version=6.10 tf_req_id=c6e7fe2d-b0f1-e48b-9611-b8a1fc65fc79 tf_resource_type=restapi_object
  diagnostic_detail=
  | A string value was provided that is not valid JSON string format (RFC 7159).
  |
  | Given Value:
   diagnostic_severity=ERROR timestamp="2026-06-12T16:32:40.491+0200"
2026-06-12T16:38:39.046+0200 [ERROR] provider.terraform-provider-restapi_v3.0.0: Response contains error diagnostic: tf_rpc=ReadResource @module=sdk.proto diagnostic_attribute="AttributeName(\"destroy_data\")"
  diagnostic_detail=
  | A string value was provided that is not valid JSON string format (RFC 7159).
  |
  | Given Value:
   diagnostic_summary="Invalid JSON String Value" tf_proto_version=6.10 tf_provider_addr=github.com/Mastercard/terraform-provider-restapi @caller=github.com/hashicorp/terraform-plugin-go@v0.29.0/tfprotov6/inte
rnal/diag/diagnostics.go:58 diagnostic_severity=ERROR tf_req_id=6878ae9f-0808-ca0a-284e-e8f030e30eb2 tf_resource_type=restapi_object timestamp="2026-06-12T16:38:39.046+0200"
2026-06-12T16:38:39.047+0200 [ERROR] vertex "restapi_object.bootstrap-indices[\"some_index_name\"]" error: Invalid JSON String Value
2026-06-12T16:38:39.047+0200 [ERROR] vertex "restapi_object.bootstrap-indices (expand)" error: Invalid JSON String Value
╷
│ Error: Invalid JSON String Value
│
│   with restapi_object.bootstrap-indices["some_index_name"],
│   on resources-index.tf line 59, in resource "restapi_object" "bootstrap-indices":
│   59:   destroy_data   = jsonencode({})
│
│ A string value was provided that is not valid JSON string format (RFC 7159).
│
│ Given Value:
│
╵

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions