Cannot save dashboards after upgrade — `variablesJSON` rejected by strict mapping on existing tenant index

Versions: 3.7.0

Describe the issue:

After updating to 3.7.0, saving any new dashboard fails with a strict_dynamic_mapping_exception. The dashboard saved object now includes the variablesJSON field (Dashboard Variables, PR #11646), but the saved-objects migration does not add this field to .kibana_* indices that existed before the update. Since those indices use dynamic: strict, the write is rejected. Restarting Dashboards does not fix it.

The save toast is empty (Dashboard '<name>' was not saved. Error:). The actual error is in the failed POST response:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "mapping set to strict, dynamic introduction of [variablesJSON] within [dashboard] is not allowed: strict_dynamic_mapping_exception"
}

After update, there was not created any new index:

green  open   .kibana_1843485230_network_14                       1   1          2            0       22kb           11kb 2026-02-11T08:53:31.411Z
green  open   .kibana_1843485230_network_13                       1   1          2            0     11.1kb          5.5kb 2025-11-12T08:56:12.426Z
green  open   .kibana_1843485230_network_12                       1   1          2            0     11.1kb          5.5kb 2025-10-27T09:26:42.604Z

On staging instance, I deleted last index .kibana_1843485230_network_14 and rebooted Dashboards. After that, I have new index .kibana_1843485230_network_1 and saving Dashboards works again.

Looks like there is a missing index migration after Dashboards update.

@joelp Have you tried to update the mapping manually as follows:

PUT /.kibana_1843485230_network_14/_mapping
{
  "properties": {
    "dashboard": {
      "properties": {
        "variablesJSON": { "type": "text", "index": false }
      }
    }
  }
}

I reproduced this exact error against a fresh OpenSearch 3.7.0 instance (same strict_dynamic_mapping_exception), applied this mapping patch, and confirmed the dashboard save succeeds afterward, while dynamic: strict continues to reject genuinely unrelated unmapped fields, so this isn’t loosening your index’s strictness, just adding the one missing field. This avoids the data loss your delete-and-recreate workaround carries.

One extra step worth doing: diff GET <tenant_index>/_mapping against a healthy tenant index, there may be other fields from later 3.x releases missing on the same stale index that haven’t surfaced as errors yet.

I also checked GitHub for existing issues covering this, nothing currently open matches. I’d recommend filing a new issue against security-dashboards-plugin referencing migrateTenantIndices() and this thread as repro, since it looks unreported.

Yes, of course, updating the mapping solves the problem. Here is the bug report.