Describe the bug
The elasticstack_kibana_security_detection_rule resource returns "Provider produced inconsistent result after apply" errors when any of the following nested list attributes are set to an empty list []:
actions
exceptions_list
severity_mapping
risk_score_mapping
related_integrations
threat
threat_mapping
Additionally, nested sub-lists within threat (e.g. threat[0].technique[0].subtechnique = []) are also affected.
The provider plans the value as an empty list (cty.ListValEmpty(...)) but the read-back after apply returns null, causing Terraform to report an inconsistency. Per the Terraform plugin framework contract, the provider's Create/Read functions must return [] (empty list) — not null — when the planned value was [].
To Reproduce
- Use the following Terraform configuration:
terraform {
required_version = ">= 1.12.0"
required_providers {
elasticstack = {
source = "elastic/elasticstack"
version = "~>0.14"
}
}
}
provider "elasticstack" {
elasticsearch {
api_key = "REDACTED"
endpoints = ["https://REDACTED.es.cloud.es.io:443/"]
}
kibana {
api_key = "REDACTED"
endpoints = ["https://REDACTED.kb.cloud.es.io:443/"]
}
}
resource "elasticstack_kibana_security_detection_rule" "repro" {
name = "Repro: empty nested lists return null"
description = "Minimal reproduction of provider bug"
type = "query"
rule_id = "00000000-0000-0000-0000-000000000001"
risk_score = 50
severity = "medium"
query = "host.name : *"
language = "kuery"
index = ["logs-*"]
enabled = false
# All of these are set to [] (empty list) in the plan,
# but the provider returns null after apply
actions = []
exceptions_list = []
threat = []
threat_mapping = []
severity_mapping = []
risk_score_mapping = []
related_integrations = []
}
- Run
terraform apply --auto-approve
- Observe 7 errors of the form:
│ Error: Provider produced inconsistent result after apply
│
│ When applying changes to elasticstack_kibana_security_detection_rule.repro,
│ provider "provider[\"registry.terraform.io/elastic/elasticstack\"]"
│ produced an unexpected new value: .actions: was
│ cty.ListValEmpty(cty.Object(map[string]cty.Type{"action_type_id":cty.String,
│ "alerts_filter":cty.Map(cty.String),
│ "frequency":cty.Object(map[string]cty.Type{"notify_when":cty.String,
│ "summary":cty.Bool, "throttle":cty.String}), "group":cty.String,
│ "id":cty.String, "params":cty.Map(cty.String), "uuid":cty.String})), but
│ now null.
│
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
Full error output for all 7 affected attributes:
│ Error: Provider produced inconsistent result after apply
│
│ When applying changes to elasticstack_kibana_security_detection_rule.repro,
│ provider "provider[\"registry.terraform.io/elastic/elasticstack\"]"
│ produced an unexpected new value: .related_integrations: was
│ cty.ListValEmpty(cty.Object(map[string]cty.Type{"integration":cty.String,
│ "package":cty.String, "version":cty.String})), but now null.
│
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵
╷
│ Error: Provider produced inconsistent result after apply
│
│ When applying changes to elasticstack_kibana_security_detection_rule.repro,
│ provider "provider[\"registry.terraform.io/elastic/elasticstack\"]"
│ produced an unexpected new value: .threat_mapping: was
│ cty.ListValEmpty(cty.Object(map[string]cty.Type{"entries":cty.List(cty.Object(
│ map[string]cty.Type{"field":cty.String,
│ "type":cty.String, "value":cty.String}))})), but now null.
│
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵
╷
│ Error: Provider produced inconsistent result after apply
│
│ When applying changes to elasticstack_kibana_security_detection_rule.repro,
│ provider "provider[\"registry.terraform.io/elastic/elasticstack\"]"
│ produced an unexpected new value: .exceptions_list: was
│ cty.ListValEmpty(cty.Object(map[string]cty.Type{"id":cty.String,
│ "list_id":cty.String, "namespace_type":cty.String, "type":cty.String})),
│ but now null.
│
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵
╷
│ Error: Provider produced inconsistent result after apply
│
│ When applying changes to elasticstack_kibana_security_detection_rule.repro,
│ provider "provider[\"registry.terraform.io/elastic/elasticstack\"]"
│ produced an unexpected new value: .risk_score_mapping: was
│ cty.ListValEmpty(cty.Object(map[string]cty.Type{"field":cty.String,
│ "operator":cty.String, "risk_score":cty.Number, "value":cty.String})), but
│ now null.
│
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵
╷
│ Error: Provider produced inconsistent result after apply
│
│ When applying changes to elasticstack_kibana_security_detection_rule.repro,
│ provider "provider[\"registry.terraform.io/elastic/elasticstack\"]"
│ produced an unexpected new value: .severity_mapping: was
│ cty.ListValEmpty(cty.Object(map[string]cty.Type{"field":cty.String,
│ "operator":cty.String, "severity":cty.String, "value":cty.String})), but
│ now null.
│
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵
╷
│ Error: Provider produced inconsistent result after apply
│
│ When applying changes to elasticstack_kibana_security_detection_rule.repro,
│ provider "provider[\"registry.terraform.io/elastic/elasticstack\"]"
│ produced an unexpected new value: .threat: was
│ cty.ListValEmpty(cty.Object(map[string]cty.Type{"framework":cty.String,
│ "tactic":cty.Object(map[string]cty.Type{"id":cty.String, "name":cty.String,
│ "reference":cty.String}),
│ "technique":cty.List(cty.Object(map[string]cty.Type{"id":cty.String,
│ "name":cty.String, "reference":cty.String,
│ "subtechnique":cty.List(cty.Object(map[string]cty.Type{"id":cty.String,
│ "name":cty.String, "reference":cty.String}))}))})), but now null.
│
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵
╷
│ Error: Provider produced inconsistent result after apply
│
│ When applying changes to elasticstack_kibana_security_detection_rule.repro,
│ provider "provider[\"registry.terraform.io/elastic/elasticstack\"]"
│ produced an unexpected new value: .actions: was
│ cty.ListValEmpty(cty.Object(map[string]cty.Type{"action_type_id":cty.String,
│ "alerts_filter":cty.Map(cty.String),
│ "frequency":cty.Object(map[string]cty.Type{"notify_when":cty.String,
│ "summary":cty.Bool, "throttle":cty.String}), "group":cty.String,
│ "id":cty.String, "params":cty.Map(cty.String), "uuid":cty.String})), but
│ now null.
│
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
Expected behavior
terraform apply should succeed without errors. When a nested list attribute is planned as an empty list [], the provider's read-back after apply should also return an empty list [] — not null. This is required by the Terraform plugin framework's consistency contract.
Debug output
Key excerpt from TF_LOG=trace terraform apply:
[TRACE] GRPCProvider.v6: ApplyResourceChange
[TRACE] provider.terraform-provider-elasticstack_v0.14.3: Received request: tf_resource_type=elasticstack_kibana_security_detection_rule tf_rpc=ApplyResourceChange
[TRACE] provider.terraform-provider-elasticstack_v0.14.3: ApplyResourceChange received no PriorState, running CreateResource
[TRACE] provider.terraform-provider-elasticstack_v0.14.3: Calling provider defined Resource Create
[DEBUG] provider.terraform-provider-elasticstack_v0.14.3: Kibana API Request Details:
...
[DEBUG] provider.terraform-provider-elasticstack_v0.14.3: Value switched to prior value due to semantic equality logic: tf_attribute_path=version tf_rpc=ApplyResourceChange
[TRACE] provider.terraform-provider-elasticstack_v0.14.3: Received downstream response: diagnostic_error_count=0 tf_rpc=ApplyResourceChange
[TRACE] NodeAbstractResourceInstance.writeResourceInstanceState: writing state object for elasticstack_kibana_security_detection_rule.repro
[TRACE] evalApplyProvisioners: elasticstack_kibana_security_detection_rule.repro is tainted, so skipping provisioning
[TRACE] maybeTainted: elasticstack_kibana_security_detection_rule.repro was already tainted, so nothing to do
[ERROR] vertex "elasticstack_kibana_security_detection_rule.repro" error: Provider produced inconsistent result after apply (x7)
The provider returns diagnostic_error_count=0 from the API call itself — the resource is successfully created. The inconsistency is detected later by Terraform when comparing the planned state against the state returned by the provider's Create function.
Screenshots
N/A
Versions (please complete the following information):
- OS: macOS (Darwin 25.3.0 arm64)
- Terraform Version: v1.14.7
- Provider version: v0.14.3
- Elasticsearch Version: 9.3.0
Additional context
Root cause: The provider's Create (and likely Read) function for elasticstack_kibana_security_detection_rule sets these nested list attributes to null when the Kibana API response omits them or returns empty arrays. Per the Terraform Plugin Framework documentation, the provider must preserve the empty-list type ([]) when the planned value was an empty list, rather than converting it to null.
All affected attributes:
| Attribute |
Schema type |
actions |
nested(list) |
exceptions_list |
nested(list) |
severity_mapping |
nested(list) |
risk_score_mapping |
nested(list) |
related_integrations |
nested(list) |
threat |
nested(list) |
threat_mapping |
nested(list) |
threat[].technique[].subtechnique |
nested(list) |
Workaround: Users can work around this by sending null instead of [] for each affected attribute:
# Instead of:
actions = []
# Use:
actions = null
Suggested fix: In the provider's Create and Read functions for this resource, when converting the Kibana API response to Terraform state, return types.ListValueMust(elemType, []attr.Value{}) instead of types.ListNull(elemType) for list attributes that were planned as empty lists but came back absent/empty from the API.
Describe the bug
The
elasticstack_kibana_security_detection_ruleresource returns"Provider produced inconsistent result after apply"errors when any of the following nested list attributes are set to an empty list[]:actionsexceptions_listseverity_mappingrisk_score_mappingrelated_integrationsthreatthreat_mappingAdditionally, nested sub-lists within
threat(e.g.threat[0].technique[0].subtechnique = []) are also affected.The provider plans the value as an empty list (
cty.ListValEmpty(...)) but the read-back after apply returnsnull, causing Terraform to report an inconsistency. Per the Terraform plugin framework contract, the provider'sCreate/Readfunctions must return[](empty list) — notnull— when the planned value was[].To Reproduce
terraform apply --auto-approveFull error output for all 7 affected attributes:
Expected behavior
terraform applyshould succeed without errors. When a nested list attribute is planned as an empty list[], the provider's read-back after apply should also return an empty list[]— notnull. This is required by the Terraform plugin framework's consistency contract.Debug output
Key excerpt from
TF_LOG=trace terraform apply:The provider returns
diagnostic_error_count=0from the API call itself — the resource is successfully created. The inconsistency is detected later by Terraform when comparing the planned state against the state returned by the provider'sCreatefunction.Screenshots
N/A
Versions (please complete the following information):
Additional context
Root cause: The provider's
Create(and likelyRead) function forelasticstack_kibana_security_detection_rulesets these nested list attributes tonullwhen the Kibana API response omits them or returns empty arrays. Per the Terraform Plugin Framework documentation, the provider must preserve the empty-list type ([]) when the planned value was an empty list, rather than converting it tonull.All affected attributes:
actionsnested(list)exceptions_listnested(list)severity_mappingnested(list)risk_score_mappingnested(list)related_integrationsnested(list)threatnested(list)threat_mappingnested(list)threat[].technique[].subtechniquenested(list)Workaround: Users can work around this by sending
nullinstead of[]for each affected attribute:Suggested fix: In the provider's Create and Read functions for this resource, when converting the Kibana API response to Terraform state, return
types.ListValueMust(elemType, []attr.Value{})instead oftypes.ListNull(elemType)for list attributes that were planned as empty lists but came back absent/empty from the API.