elastic/elasticsearch · error · IllegalStateException

index [%s] is the write index for data stream [%s] and canno

Error message

index [%s] is the write index for data stream [%s] and cannot be replaced

What it means

IllegalStateException from the downsample 'delete source and add downsample' path when the source backing index is the data stream's current write index. Deleting the write index would orphan the stream's write target, so the operation is refused.

Source

Thrown at modules/data-streams/src/main/java/org/elasticsearch/datastreams/lifecycle/downsampling/DeleteSourceAndAddDownsampleToDS.java:112

                    "unable find source index [{}] but adding index [{}] to data stream [{}]",
                    sourceBackingIndex,
                    downsampleIndex,
                    dataStreamName
                );
                ProjectMetadata.Builder newProject = ProjectMetadata.builder(project)
                    .put(dataStream.addBackingIndex(project, downsampleIndexMeta.getIndex()));
                return ClusterState.builder(state).putProjectMetadata(newProject).build();
            }
        } else {
            DataStream sourceParentDataStream = sourceIndexAbstraction.getParentDataStream();
            if (sourceParentDataStream != null && sourceParentDataStream.getWriteIndex().getName().equals(sourceBackingIndex)) {
                String errorMessage = String.format(
                    Locale.ROOT,
                    "index [%s] is the write index for data stream [%s] and cannot be replaced",
                    sourceBackingIndex,
                    sourceParentDataStream.getName()
                );
                throw new IllegalStateException(errorMessage);
            }

            IndexMetadata sourceIndexMeta = project.index(sourceBackingIndex);
            assert sourceIndexMeta != null
                : "the source index abstraction exists in the indices lookup, so the index metadata must "
                    + "exist in the same cluster state metadata";
            // the source index exists so let's start by deleting it
            state = MetadataDeleteIndexService.deleteIndices(state.projectState(projectId), Set.of(sourceIndexMeta.getIndex()), settings);
            DataStream dataStream = state.metadata().getProject(projectId).dataStreams().get(dataStreamName);
            if (sourceParentDataStream != null) {
                assert sourceParentDataStream.getName().equals(dataStreamName)
                    : "the backing index must be part of the provided data "
                        + "stream ["
                        + dataStreamName
                        + "] but it is instead part of data stream ["
                        + sourceParentDataStream.getName()
                        + "]";
                // both indices exist, let's copy the origination date from the source index to the downsample index

View on GitHub (pinned to db6a809a66)

Solutions

  1. Rollover the data stream first so the target index is no longer the write index
  2. Target only sealed/non-write backing indices for downsampling
  3. If deleting was the intent, use the standard index delete API after the index is no longer the write index

Example fix

// before: downsample targets .ds-mylogs-2025-01-01-000001 which is the write index
POST mylogs/_rollover
POST .ds-mylogs-2025-01-01-000001/_downsample/1h
// after: the rolled-over index is no longer the write index and can be downsampled
Defensive patterns

Strategy: validation

Validate before calling

// Never downsample the write index; check before scheduling:
String writeIndex = dataStream.getWriteIndex().getName();
if (writeIndex.equals(targetIndex)) {
    rollover(dataStream.getName()); // or skip/pick a different target
}

Try / catch

try { downsample(targetIndex); }
catch (IllegalStateException e) {
    if (e.getMessage().contains("write index")) { rollover(dsName); downsample(targetIndex); }
    else throw e;
}

Prevention

When it happens

Trigger: DeleteSourceAndAddDownsampleToDS is asked to downsample-and-replace an index whose name equals dataStream.getWriteIndex().getName(). The downsample job (or manual delete_backing_index) targeted the live write index instead of a sealed backing index.

Common situations: Running downsampling on the newest backing index without rolling over first; scheduler mis-selecting the write index; manual _modify_data_streams delete_backing_index on the current write index.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/558bcc4119982ef7. Report an issue: GitHub.