{"record":{"id":"558bcc4119982ef7","repo":"elastic/elasticsearch","slug":"index-s-is-the-write-index-for-data-stream-s","errorCode":null,"errorMessage":"index [%s] is the write index for data stream [%s] and cannot be replaced","messagePattern":"index \\[(.+?)\\] is the write index for data stream \\[(.+?)\\] and cannot be replaced","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"modules/data-streams/src/main/java/org/elasticsearch/datastreams/lifecycle/downsampling/DeleteSourceAndAddDownsampleToDS.java","lineNumber":112,"sourceCode":"                    \"unable find source index [{}] but adding index [{}] to data stream [{}]\",\n                    sourceBackingIndex,\n                    downsampleIndex,\n                    dataStreamName\n                );\n                ProjectMetadata.Builder newProject = ProjectMetadata.builder(project)\n                    .put(dataStream.addBackingIndex(project, downsampleIndexMeta.getIndex()));\n                return ClusterState.builder(state).putProjectMetadata(newProject).build();\n            }\n        } else {\n            DataStream sourceParentDataStream = sourceIndexAbstraction.getParentDataStream();\n            if (sourceParentDataStream != null && sourceParentDataStream.getWriteIndex().getName().equals(sourceBackingIndex)) {\n                String errorMessage = String.format(\n                    Locale.ROOT,\n                    \"index [%s] is the write index for data stream [%s] and cannot be replaced\",\n                    sourceBackingIndex,\n                    sourceParentDataStream.getName()\n                );\n                throw new IllegalStateException(errorMessage);\n            }\n\n            IndexMetadata sourceIndexMeta = project.index(sourceBackingIndex);\n            assert sourceIndexMeta != null\n                : \"the source index abstraction exists in the indices lookup, so the index metadata must \"\n                    + \"exist in the same cluster state metadata\";\n            // the source index exists so let's start by deleting it\n            state = MetadataDeleteIndexService.deleteIndices(state.projectState(projectId), Set.of(sourceIndexMeta.getIndex()), settings);\n            DataStream dataStream = state.metadata().getProject(projectId).dataStreams().get(dataStreamName);\n            if (sourceParentDataStream != null) {\n                assert sourceParentDataStream.getName().equals(dataStreamName)\n                    : \"the backing index must be part of the provided data \"\n                        + \"stream [\"\n                        + dataStreamName\n                        + \"] but it is instead part of data stream [\"\n                        + sourceParentDataStream.getName()\n                        + \"]\";\n                // both indices exist, let's copy the origination date from the source index to the downsample index","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/data-streams/src/main/java/org/elasticsearch/datastreams/lifecycle/downsampling/DeleteSourceAndAddDownsampleToDS.java#L94-L130","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rollover the data stream first so the target index is no longer the write index","Target only sealed/non-write backing indices for downsampling","If deleting was the intent, use the standard index delete API after the index is no longer the write index"],"exampleFix":"// before: downsample targets .ds-mylogs-2025-01-01-000001 which is the write index\nPOST mylogs/_rollover\nPOST .ds-mylogs-2025-01-01-000001/_downsample/1h\n// after: the rolled-over index is no longer the write index and can be downsampled","handlingStrategy":"validation","validationCode":"// Never downsample the write index; check before scheduling:\nString writeIndex = dataStream.getWriteIndex().getName();\nif (writeIndex.equals(targetIndex)) {\n    rollover(dataStream.getName()); // or skip/pick a different target\n}","typeGuard":null,"tryCatchPattern":"try { downsample(targetIndex); }\ncatch (IllegalStateException e) {\n    if (e.getMessage().contains(\"write index\")) { rollover(dsName); downsample(targetIndex); }\n    else throw e;\n}","preventionTips":["Downsample only indices older than the current write index","Build a downsample candidate selector that excludes the write index","Wire rollover into the lifecycle policy so write indices move on schedule"],"tags":["downsampling","data-streams","write-index","lifecycle"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}