Skip to content

[BUG] Composable index template mapping can prevent creating an index if mappings conflict #16340

Closed
@dbwiddis

Description

@dbwiddis

Describe the bug

In the index templates documentation for Composable index templates, it states:

Settings and mappings that you specify directly in the create index request override any settings or mappings specified in an index template and its component templates.

This documentation is not accurate.

Specifically, overriding is not possible if the conflicting type can't be merged (e.g., between object and nested, field and object, etc.). Overriding only occurs on "leaf" components. (See ab65a57)

Worse, this mapping conflict prevents index creation, including system indices.

A user could accidentally add a wrong mapping and potentially prevent a node from even starting up: opensearch-project/observability#1872

Related component

Indexing

To Reproduce

  1. Create a component template with an object or nested mapping for a field ("error" in this case):
PUT _component_template/error_mapping_template
{
  "template": {
    "mappings": {
      "properties": {
        "error" : {
          "type": "nested",
          "properties": {
            "message": {
              "type": "text"
            },
            "status": {
              "type": "integer"
            }
          }
        }
      }
    }
  }
}
  1. Create an index template using that composable template mapping:
PUT _index_template/match_all_template
{
  "index_patterns": [
    "*"
  ],
  "template": {
    "settings": {}
  },
  "priority": 10,
  "composed_of": [
    "error_mapping_template"
  ],
  "version": 1
}
  1. Attempt to create an index with a conflicting field mapping (including a system index):
PUT /.plugins-foo-system-index
{
  "mappings": {
    "properties": {
      "error": {
        "type": "text"
      }
    }
  }
}
  1. Receive the below error, and observe that the index did not successfully create.
{
    "error": {
        "root_cause": [
            {
                "type": "illegal_argument_exception",
                "reason": "can't merge a non object mapping [error] with an object mapping"
            }
        ],
        "type": "illegal_argument_exception",
        "reason": "can't merge a non object mapping [error] with an object mapping"
    },
    "status": 400
}

Expected behavior

The mapping specified in the create index API call overrides the template mapping, and the index is actually created.

Additional Details

Plugins

N/A. Reproduced on a local cluster using HEAD of 2.x branch, using ./gradlew clean run.

However, this is a significant issue for any plugin that uses a system index. It's a critical issue for plugins that prevent a node from starting up if the system index is not created.

Host/Environment (please complete the following information):

Reproducable locally on macOS; occurred on a production cluster on AOS, OpenSearch version 2.15

Additional context

This is significant in that:

  1. Many plugins use system indices
  2. These index templates are in control of the user and yet conflict with system indices
  3. There's no easy way for a plugin, when creating a system index, to avoid this conflict or specify "don't use templates at all", essentially allowing a user to break several plugins without really even knowing it.

In this case, to work around the bug I had to create a (temporary) higher priority matching template with an empty object in the mapping field to prevent the incompatible mapping.

Stack trace leading to the error:

java.lang.IllegalArgumentException: can't merge a non object mapping [error] with an object mapping
        at org.opensearch.index.mapper.ObjectMapper.merge(ObjectMapper.java:767) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.index.mapper.ObjectMapper.doMerge(ObjectMapper.java:798) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.index.mapper.RootObjectMapper.doMerge(RootObjectMapper.java:364) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.index.mapper.ObjectMapper.merge(ObjectMapper.java:771) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.index.mapper.RootObjectMapper.merge(RootObjectMapper.java:359) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.index.mapper.Mapping.merge(Mapping.java:130) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.index.mapper.DocumentMapper.merge(DocumentMapper.java:310) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.index.mapper.MapperService.internalMerge(MapperService.java:521) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.index.mapper.MapperService.internalMerge(MapperService.java:483) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.index.mapper.MapperService.merge(MapperService.java:447) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.cluster.metadata.MetadataCreateIndexService.updateIndexMappingsAndBuildSortOrder(MetadataCreateIndexService.java:1441) ~[opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.cluster.metadata.MetadataCreateIndexService.lambda$applyCreateIndexWithTemporaryService$3(MetadataCreateIndexService.java:523) [opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.indices.IndicesService.withTempIndexService(IndicesService.java:982) [opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.cluster.metadata.MetadataCreateIndexService.applyCreateIndexWithTemporaryService(MetadataCreateIndexService.java:514) [opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.cluster.metadata.MetadataCreateIndexService.applyCreateIndexRequestWithV2Template(MetadataCreateIndexService.java:783) [opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.cluster.metadata.MetadataCreateIndexService.applyCreateIndexRequest(MetadataCreateIndexService.java:457) [opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.cluster.metadata.MetadataCreateIndexService.applyCreateIndexRequest(MetadataCreateIndexService.java:483) [opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.cluster.metadata.MetadataCreateIndexService$1.execute(MetadataCreateIndexService.java:389) [opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]
        at org.opensearch.cluster.ClusterStateUpdateTask.execute(ClusterStateUpdateTask.java:67) [opensearch-2.18.0-SNAPSHOT.jar:2.18.0-SNAPSHOT]

Metadata

Metadata

Assignees

Labels

IndexingIndexing, Bulk Indexing and anything related to indexingbugSomething isn't workingv2.19.0Issues and PRs related to version 2.19.0v3.0.0Issues and PRs related to version 3.0.0

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions