Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When application.data contains an array getting Error expected type 'string' #240

Open
Aaron-Ritter opened this issue Oct 9, 2023 · 7 comments

Comments

@Aaron-Ritter
Copy link

When the following data is stored in the application data in a valid json format:

{
  "defaultLanguage" : "de",
  "languages" : [ "de", "fr", "en" ]
}

It will complain with the following error:

│ Error: application.data: data.languages: '' expected type 'string', got unconvertible type '[]interface {}', value: '[de fr en]'
│ 
│   with fusionauth_application.syrakus-oldcapitol,
│   on syrakus-oldcapitol.tf line 6, in resource "fusionauth_application" "syrakus-oldcapitol":
│    6: resource "fusionauth_application" "syrakus-oldcapitol" {
@Aaron-Ritter
Copy link
Author

Aaron-Ritter commented Jan 4, 2024

related issues #256 #63

The current provider only validates for schema.TypeMap:

"data": {
Type: schema.TypeMap,
Optional: true,
Description: "An object that can hold any information about the Application that should be persisted.",
},

Where for user.data it does some json related function in dataToUserRequest:

resourceData, subDiags := jsonStringToMapStringInterface(data.Get("data").(string))
if subDiags != nil {
diags = append(diags, subDiags...)
}

with jsonStringToMapStringInterface

func jsonStringToMapStringInterface(in string) (out map[string]interface{}, diags diag.Diagnostics) {
out = map[string]interface{}{}
if strings.TrimSpace(in) == "" {
return out, nil
}
if err := json.Unmarshal([]byte(in), &out); err != nil {
fmt.Printf("jsonStringToMapStringInterface: %s", err)
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Unable to transform data to expected type",
Detail: fmt.Sprintf(
"Error unmarshalling data from an expected JSON encoded string to map[string]interface{}.\n"+
"Please make sure you have wrapped your HCL with jsonencode."+
"For example, 'jsonencode({ hello = \"world\" })'.\n\n"+
"error: %s\n",
err,
),
})
}
return
}

and userResponseToData:

if userData, diags := mapStringInterfaceToJSONString(resp.User.Data); diags != nil {
return diags
} else if err := data.Set("data", userData); err != nil {
return diag.Errorf("user.data: %s", err.Error())
}

with mapStringInterfaceToJSONString

func mapStringInterfaceToJSONString(in map[string]interface{}) (out string, diags diag.Diagnostics) {
if len(in) == 0 {
return "", nil
}
outBytes, err := json.MarshalIndent(in, "", " ")
if err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Unable to transform data to expected type",
Detail: fmt.Sprintf(
"Error marshalling data from a map[string]interface{} to a JSON string.\n"+
"error: %s\n",
err,
),
})
return
}
return string(outBytes), nil
}

@Aaron-Ritter
Copy link
Author

@TomKimber thanks for the recent update.

I wanted to update the ticket to reconfirm the bug with 0.2.0, when not defining it the plan crashes because it is checking the applied data in the application.

Image

│ Error: application.data: data.requestedData: '' expected type 'string', got unconvertible type 'map[string]interface {}', value: 'map[addresses:required bankAccounts:required communications:required dietaryPreferences:required emergencyContact:required employmentData:required]'
│ 
│   with fusionauth_application.syrakus-demo1,
│   on application-syrakus-demo1.tf line 1, in resource "fusionauth_application" "syrakus-demo1":
│    1: resource "fusionauth_application" "syrakus-demo1" {

When defining it in the specification the terraform plan:

resource "fusionauth_application" "syrakus-demo1" {
...
  data = {
...
    "defaultLanguage" : "en",
    "languages" : [ "en", "fr", "de", "it" ]
  }
...
}

it fails with the following error:

│ Error: Incorrect attribute value type
│ 
│   on application-syrakus-demo1.tf line 4, in resource "fusionauth_application" "syrakus-demo1":
│    4:   data = {
...
│   11:     "defaultLanguage" : "en",
│   12:     "languages" : [ "en", "fr", "de", "it" ]
│   13:   }
│ 
│ Inappropriate value for attribute "data": element "languages": string required.

@TomKimber
Copy link
Collaborator

Thanks for reconfirming this issue with the current version @Aaron-Ritter. I'm aware of the inconsistent implementation of the "data" field across resources you've highlighted. I did look at fixing this as part of the last release but it wouldn't be possible without breaking changes to the schemas of the resources.

I'll take another look at this to see if this can be fixed without breaking changes. If not, it'll be fixed as part of a larger release in the near future.

@Aaron-Ritter
Copy link
Author

Aaron-Ritter commented Feb 11, 2025

Thanks for the clarification @TomKimber and great work!

To be fair with 0.2.0 some of the configurations had to be updated to follow the new spec, so if you are referring to this as a breaking change, at least from our point of view is acceptable.

In fact our deployment is broken and i guess anyone facing this has a broken upgrade with terraform too. We are only able to use it for restaging our environment (basically the first inital deployment) but as soon these data sets are populated by using it terraform breaks.

update

What i mean by breaking change is that e.g. form_configuration changed from:

  form_configuration = [
    {
      admin_registration_form_id = var.fusionauth_default_admin_registration_form_id
      self_service_form_id       = var.fusionauth_default_user_self_service_form_id
    },
  ]

to:

  form_configuration {
    admin_registration_form_id = var.fusionauth_default_admin_registration_form_id
    self_service_form_id       = var.fusionauth_default_user_self_service_form_id
  }

@TomKimber
Copy link
Collaborator

@Aaron-Ritter What version of the provider were you updating from? I've just tested with the prior release (v0.1.111) and I'm not able to replicate. When I try to use the format in your "from" version Terraform throws " Inappropriate value for attribute "form_configuration": list of object required". Certainly, your "to" example should have been the format for both versions.

I suspect the Data field handling consolidation will require some breaking changes for some resources. Once that's nearing release, I'll note that both here and in the release notes.

@Aaron-Ritter
Copy link
Author

Aaron-Ritter commented Feb 12, 2025

Thanks @TomKimber, a info would be great in the release notes. And to be fair, if it is similar to the issues i faced now terraform plan is reviewing it correctly with a detailed error. And once fixing it in the IDE it is even suggesting the correct format if you use a IDE which supports the terraform format/provider.

To clarify, do you consider it a breaking change because it would require a complete re-staging with a new version of the terraform provider or similar to what i experienced now by adjusting the configuration for it to work again with my existing state?

The last version i tested it properly was 0.1.108. Another example was from:

    authenticator = [
      {
        enabled = true
      }
    ]

to:

    authenticator {
      enabled = true
    }

@TomKimber
Copy link
Collaborator

TomKimber commented Feb 12, 2025

@Aaron-Ritter Apologies - My definition of a breaking change here is a change that requires users to change their existing config to run a plan/apply following a provider version update e.g. I would consider your examples a result of breaking changes. The Data field change would be an example of this requiring users to change their existing Terraform configuration if they're currently passing maps into the Data field. Any state migrations required would be handled by the provider. This would not require a complete re-staging of your environments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants