Skip to content
ohsudo, Home
Databases

Elasticsearch "flood-stage watermark" and read-only indices: free the disk, then check the block

Fix Elasticsearch "disk usage exceeded flood-stage watermark, index has read-only-allow-delete block": free disk space, check allocation and remove the block if needed.

Intermediate4 min readApplies to Elasticsearch 7.x · Elasticsearch 8.x · OpenSearch · Kibana · Docker

by OhSudo ··

Checked on real software: Elasticsearch · November 2026How we check

Not sure this is your cause?Find it step by step: Disk full or out of memory →

{"type":"cluster_block_exception","reason":"index [logs-2026.11.06] blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block; for more information, see https://www.elastic.co/guide/en/elasticsearch/reference/8.17/fix-watermark-errors.html];"}

Writes fail, with HTTP status 429. Older versions word it differently:

FORBIDDEN/12/index read-only / allow delete (api)

Elasticsearch watches each node’s disk, and as one fills up, it acts. At 95% it makes every index with a shard on that node read-only, to protect the node from running out completely. Your data’s safe. New writes are refused, while reads and deletes still work.

  1. low: 85%no new shards on this node
  2. high: 90%tries to move shards away
  3. flood_stage: 95%indices become read-only(breaks here)
Elasticsearch watches each node's disk, as a share of the whole disk. At the flood stage it makes the indices on that node read-only to keep it from filling up; reads and deletes still work.

TL;DR

Terminal window
curl -s 'localhost:9200/_cat/allocation?v'
df -h /var/lib/elasticsearch

Free up space, usually by deleting old indices. Since 7.4 the block clears itself once usage drops below the high watermark. If it stays:

Terminal window
curl -X PUT 'localhost:9200/_all/_settings' -H 'Content-Type: application/json' \
-d '{"index.blocks.read_only_allow_delete": null}'

The three watermarks

Setting Default What happens
low 85% No new shards are placed on this node
high 90% Elasticsearch tries moving shards off this node
flood_stage 95% Indices on this node become read-only

Note that it’s a percentage of the whole disk, and doesn’t only count Elasticsearch’s data. On a 2 TB disk, 95% leaves 100 GB free, and you can still be blocked. Section 5 has a setting for that.

1. See the disks

Terminal window
curl -s 'localhost:9200/_cat/allocation?v&h=node,disk.percent,disk.used,disk.avail,disk.total,shards'
node disk.percent disk.used disk.avail disk.total shards
node-1 96 480gb 20gb 500gb 312

Add -u elastic:password and use https:// if security is on, as it is by default since 8.0. Then see who’s using the space on that disk:

Terminal window
curl -s 'localhost:9200/_cat/indices?v&s=store.size:desc&h=index,docs.count,store.size,pri,rep' | head -20
sudo du -xh --max-depth=1 /var | sort -h | tail

If the disk’s filled by something other than Elasticsearch, such as logs, then no space left on device helps you find it.

2. Free some space

Deleting old indices is the quickest way, and it’s allowed under this block:

Terminal window
curl -X DELETE 'localhost:9200/logs-2026.09.*'

Check what a pattern matches before deleting, with _cat/indices/logs-2026.09.*. In 8.x, wildcard deletes may be refused by action.destructive_requires_name, in which case you name them one by one.

Other options:

  • Take away replicas from old indices, if you can live with less safety for that data. It halves their size, as in {"index.number_of_replicas": 0}.
  • Move shards away by adding a node or a bigger disk. Elasticsearch rebalances by itself.
  • Grow the volume, which on the cloud is often the quickest.

Don’t delete files from /var/lib/elasticsearch by hand. Those are shards, and that corrupts the indices.

3. Check the block is gone

Since 7.4, it’s removed automatically when usage falls below the high watermark. So freeing up just a bit won’t do it, as you’ve got to go below 90%. Check:

Terminal window
curl -s 'localhost:9200/_all/_settings/index.blocks.read_only_allow_delete?pretty'

If it’s still there, on an older version or because you can’t wait, remove it:

Terminal window
curl -X PUT 'localhost:9200/_all/_settings' -H 'Content-Type: application/json' \
-d '{"index.blocks.read_only_allow_delete": null}'

If the disk is still full, it comes back within a short time, since the check runs every 30 seconds by default.

4. Kibana stuck too

Kibana stores its own data in indices, so it may report errors while saving:

FORBIDDEN/12/index read-only / allow delete (api)

That’s the same block on .kibana*. Once there’s space, the same request as in section 3 clears it, if that doesn’t happen by itself. Restart Kibana if it’s still unhappy.

5. Make sure it doesn’t return

Delete old data automatically. Index Lifecycle Management deletes or moves data by age, so you don’t have to remember to:

Terminal window
curl -X PUT 'localhost:9200/_ilm/policy/logs-30d' -H 'Content-Type: application/json' -d '{
"policy": { "phases": {
"hot": { "actions": { "rollover": { "max_age": "1d", "max_primary_shard_size": "50gb" } } },
"delete": { "min_age": "30d", "actions": { "delete": {} } }
} }
}'

Then attach it to your index template. On OpenSearch, the same job goes by Index State Management.

On large disks, use absolute values, as percentages leave too much unused:

Terminal window
curl -X PUT 'localhost:9200/_cluster/settings' -H 'Content-Type: application/json' -d '{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": "100gb",
"cluster.routing.allocation.disk.watermark.high": "50gb",
"cluster.routing.allocation.disk.watermark.flood_stage": "20gb"
}
}'

Absolute values mean free space that must remain, and they have to be used for all three. It’s fine to raise limits a bit for a rare situation, but it only buys time.

Set an alert on disk usage at 80%, so you know before it reaches the low watermark.

6. Docker and single-node

A single node with discovery.type=single-node still follows these limits, and on a laptop a full disk is easy to reach. So check df -h and docker system df.

For a local test only, you can turn the check off:

environment:
- cluster.routing.allocation.disk.threshold_enabled=false

Never do that in production, where a truly full disk can corrupt data.

Warning

Removing the block while the disk stays full only delays the problem, and makes it worse. If the disk fills up completely, Elasticsearch can fail its writes partway, and recovery gets much harder than deleting a few old indices.

Shell, we have a problem!

Similar, but different: cluster_block_exception with SERVICE_UNAVAILABLE/1/state not recovered means the cluster hasn’t formed. index.blocks.write or read_only set to true are blocks that a person or tool set, and that don’t go away by themselves. es_rejected_execution_exception (also a 429) means the queue is full, because of too much load rather than disk. And max virtual memory areas vm.max_map_count [65530] is too low is a startup problem: run sudo sysctl -w vm.max_map_count=262144.

Found this useful? Share it.

Found a mistake? Let us know at contact@ohsudo.com.

Articles

Related articles