elastic/elasticsearch · error · IllegalArgumentException
Cannot add dynamic templates that define dimension fields on
Error message
Cannot add dynamic templates that define dimension fields on an existing index with index.dimensions. Please change the index template and roll over the data stream instead of modifying the mappings of the backing indices.
What it means
Thrown by DataStreamIndexSettingsProvider.onUpdateMappings when an existing tsdb index (one with index.dimensions set) receives a mapping update whose dynamic templates do not cover all the existing dimension fields. tsdb dimension sets are immutable per backing index; new dimensions must come via a new generation through template + rollover, not by editing live backing index mappings.
Source
Thrown at modules/data-streams/src/main/java/org/elasticsearch/datastreams/DataStreamIndexSettingsProvider.java:206
* {@link IndexMetadata#getTimeSeriesDimensions()}.
* Changing fom {@link IndexMetadata#INDEX_DIMENSIONS} to {@link IndexMetadata#INDEX_ROUTING_PATH}
* is not allowed because it would violate the invariant that the same input document always results
* in the same _id and _tsid.
* Otherwise, data duplication or translog replay issues could occur.
*/
@Override
public void onUpdateMappings(IndexMetadata indexMetadata, DocumentMapper documentMapper, Settings.Builder additionalSettings) {
List<String> indexDimensions = indexMetadata.getTimeSeriesDimensions();
if (indexDimensions.isEmpty()) {
return;
}
assert IndexMode.isTsdb(indexMetadata.getIndexMode());
List<String> newIndexDimensions = new ArrayList<>(indexDimensions.size());
boolean matchesAllDimensions = findDimensionFields(newIndexDimensions, documentMapper);
boolean hasChanges = indexDimensions.size() != newIndexDimensions.size()
&& new HashSet<>(indexDimensions).equals(new HashSet<>(newIndexDimensions)) == false;
if (matchesAllDimensions == false) {
throw new IllegalArgumentException(
"Cannot add dynamic templates that define dimension fields on an existing index with "
+ INDEX_DIMENSIONS.getKey()
+ ". "
+ "Please change the index template and roll over the data stream "
+ "instead of modifying the mappings of the backing indices."
);
} else if (hasChanges) {
additionalSettings.putList(INDEX_DIMENSIONS.getKey(), newIndexDimensions);
}
}
/**
* Find fields in mapping that are time_series_dimension enabled.
* Using MapperService here has an overhead, but allows the mappings from template to
* be merged correctly and fetching the fields without manually parsing the mappings.
* <p>
* Alternatively this method can instead parse mappings into map of maps and merge that and
* iterate over all values to find the field that can serve as routing value. But this requiresView on GitHub (pinned to db6a809a66)
Solutions
- Update the composable index template defining the dimensions, then roll over the data stream so new backing indices get the new dimension set.
- Do not PUT _mapping on individual tsdb backing indices to change dimensions.
- If a one-off mapping fix is truly needed, reindex into a new correctly-templated stream.
Defensive patterns
Strategy: validation
Validate before calling
// Before PUT _mapping on a tsdb index, detect dimension changes and refuse.
const existing = new Set(indexMetadata.time_series_dimensions || []);
const covered = new Set(computeDimensionsFromTemplates(newDocumentMapper));
for (const d of existing) {
if (!covered.has(d)) throw new Error(`dimension [${d}] no longer covered; update template and rollover instead`);
} Prevention
- Never edit dimension mappings on live tsdb backing indices; evolve via template + rollover.
- Treat index.time_series.dimensions as immutable per backing-index generation.
When it happens
Trigger: PUT _mapping on a backing index that has index.time_series.dimensions set, where the supplied dynamic templates fail findDimensionFields coverage for the existing dimension list. Adding/removing/redefining dimension templates against a live tsdb backing index.
Common situations: Trying to evolve dimension fields by editing mappings directly instead of updating the index template and rolling over; automation that applies the same mapping update to all backing indices.
Related errors
- backing index [%s] in tsdb mode doesn't have the [%s] index
- failed to parse value%s for setting [%s], must be lower than
- Cannot create past TSDB backing index for data stream [{}] b
- vector dimensions incompatible
- vector dimensions incompatible: {}!= {} x {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/442734186c9be185.
Report an issue: GitHub.