📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

适用版本: 6.8-8.9

1. 错误异常的基本描述 #

cannot create snapshot in a readonly repository 是一个语义非常明确的异常,表示你正在尝试向一个被标记为只读的快照仓库执行写操作。这里的问题不在分片、节点或查询,而在仓库元数据本身。只读仓库允许读取、列出和恢复某些内容,但不允许创建新快照、删除快照或做其他写入型修改。

从当前源码片段可以看出,Elasticsearch 在真正提交快照任务前会先检查 repository.isReadOnly(),如果仓库是只读的,就会立即抛出 RepositoryException(..., "cannot create snapshot in a readonly repository")。这意味着问题在请求入口阶段就已经决定了,不需要再去查搜索执行或分片状态。

常见现象 #

  • 在执行 PUT /_snapshot/{repository}/{snapshot} 时请求立即失败,错误返回中通常包含 repository_exception,原因直接写明该仓库是只读的。
  • 仓库本身可能能正常查看、校验、甚至用于恢复,但一旦执行创建快照等写操作就会被拒绝。
  • 常见场景包括:仓库为了迁移或共享恢复被明确设置为只读、对象存储权限只给了读权限、某个环境为了防误操作把仓库改成了只读。
  • 从业务侧看,表现通常是备份任务无法执行,但恢复查询、仓库查看等读操作可能是正常的。

典型报错与异常栈 #

这类错误通常会与下面这些异常一起出现:

  • repository_exception
  • cannot create snapshot in a readonly repository
  • repository is readonly

常见返回通常类似下面这样:

{
	"error": {
		"type": "repository_exception",
		"reason": "[my_backup_repo] cannot create snapshot in a readonly repository"
	},
	"status": 500
}

2. 为什么会发生这个错误 #

这个错误的本质是“你的操作是写操作,但目标仓库的当前策略不允许写入”。它不是偶发异常,而是一个明确的策略冲突。只要仓库仍然是只读状态,重复重试也不会成功。

常见原因通常包括:

  • 仓库在创建或更新时明确配置了 readonly: true
  • 当前仓库用于跨集群共享恢复场景,被设计成只读,不能承担备份写入。
  • 底层对象存储或文件系统权限本身只有读权限,即使仓库元数据看起来正常,实际也无法写入新快照。
  • 运维人员在迁移、灾备演练或安全加固时把仓库改成了只读,但上层快照任务仍然尝试写入。

3. 如何排查和解决这个异常和解决这个异常 #

建议按“先确认仓库是否只读,再确认这是预期策略还是误配置”的顺序处理:

  1. 查看仓库当前配置,确认 readonly 是否为 true
  2. 确认该仓库本来就是恢复用途的只读仓库,还是被误改成了只读。
  3. 检查底层文件系统或对象存储权限,确认即使改回可写,底层权限也允许写入。
  4. 如果业务上确实需要写快照,更新仓库为可写或改用专门的写仓库。

相关 Elasticsearch API 及调用说明 #

1. 查看仓库配置 #

curl -X GET "http://localhost:9200/_snapshot/my_backup_repo?pretty"

重点关注仓库 settings 中是否存在 readonly: true 或其他写入受限设置。

2. 创建快照 #

curl -X PUT "http://localhost:9200/_snapshot/my_backup_repo/snapshot_2026_03_31?wait_for_completion=true&pretty"

如果仓库是只读的,这个调用会立即失败,并返回只读相关错误。

3. 更新仓库配置 #

如果业务上确实需要把仓库改回可写,可以重新提交仓库配置:

curl -X PUT "http://localhost:9200/_snapshot/my_backup_repo?pretty" \
	-H 'Content-Type: application/json' \
	-d '{
		"type": "fs",
		"settings": {
			"location": "/mount/backups/es",
			"readonly": false
		}
	}'

更新前必须确认底层存储权限真的允许写入,否则改成 readonly: false 也无法真正解决问题。

4. 校验仓库 #

curl -X POST "http://localhost:9200/_snapshot/my_backup_repo/_verify?pretty"

这一步适合确认仓库在切换配置后是否真的可被节点正常访问。

排查时需要注意的问题 #

  • 不要把只读仓库误当成异常状态,有些场景下只读是设计使然。
  • 如果仓库用于跨集群共享或恢复,强行改成可写可能引入新的风险。
  • 仓库元数据改成可写之前,一定要确认底层对象存储或共享目录权限已经同步调整。

4. 如何解决这个错误 #

常用修复思路 #

  • 如果仓库本来就应该可写,修正 readonly 配置并同步修复底层存储权限。
  • 如果仓库本来就是恢复用途的只读仓库,改用专门的写仓库创建快照,不要强行复用只读仓库。
  • 对快照策略、SLM 任务和恢复仓库做明确职责划分,避免读写混用。

后续注意事项与推荐建议 #

  • 为每个仓库标注用途,例如“只读恢复仓库”“可写备份仓库”,避免运维混用。
  • 对快照任务执行前增加仓库状态检查,提前发现只读冲突。
  • 把仓库读写策略纳入运维变更记录,避免误改后难以回溯。

借助 INFINI 产品提升排障效率 #

  • INFINI Console 适合观察仓库相关错误趋势和快照任务状态,帮助区分配置问题与运行期问题。
  • INFINI Gateway 适合保留运维接口审计记录,便于追踪谁修改了仓库策略。

5. 小结 #

cannot create snapshot in a readonly repository 的关键不是快照逻辑失败,而是写策略不允许。只要仓库仍是只读,重试没有意义。

最有效的处理方式是先确认这是不是预期设计,再决定是改回可写还是切换到正确的写仓库。只要把仓库职责边界划清,这类错误通常很容易避免。

附:日志上下文 #

下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:

// TODO: create snapshot UUID in CreateSnapshotRequest and make this operation idempotent to cleanly deal with transport layer
 // retries
 final SnapshotId snapshotId = new SnapshotId(snapshotName; UUIDs.randomBase64UUID()); // new UUID for the snapshot
 Repository repository = repositoriesService.repository(request.repository());
 if (repository.isReadOnly()) {
 listener.onFailure(new RepositoryException(repository.getMetadata().name(); "cannot create snapshot in a readonly repository"));
 return;
 }
 submitCreateSnapshotRequest(request; listener; repository; new Snapshot(repositoryName; snapshotId); repository.getMetadata());
 }