Restoring indices from snapshot with rename_replacement results in unexpected index name suffix

Versions (relevant - OpenSearch/Dashboard/Server OS/Browser):

v 1.3.2

Describe the issue:

When I restore an index and use the rename_replacement option I’m getting an unexpected suffix on the index name.

Example restore command:

curl -ksSL -u "$USER_AUTH" -XPOST -H 'Content-Type: application/json' \
https://localhost:9200/_snapshot/log-archive/2021/_restore -d \
'{"rename_pattern": ".*", "rename_replacement": "restored-$0", "indices": "*-foo-2021.04", "ignore_index_settings": ["index.routing.allocation.require.box_type"]}'

Expected restored index name:

restored-server-logs-foo-2021.04

What I get instead (note the restored- suffix):

restored-server-logs-foo-2021.04restored-

I guess this must be happening due to the "rename_replacement": "restored-$0" field, but I don’t understand exactly why it is happening. Any ideas?

Configuration:

S3 storage for snapshots, though not sure if it is relevant.

Relevant Logs or Screenshots:

n/a

Hi, try to change the group reference in the replacement pattern to “$1” instead of “$0” and
rename_pattern.

“$1” refers to the first capture group

{
  "rename_pattern": "^(.*)",
  "rename_replacement": "restored-$1",
  "indices": "*-foo-2021.04",
  "ignore_index_settings": [
    "index.routing.allocation.require.box_type"
  ]
}

Hi, thanks for the response!

Yes that will probably work. However what I wanted to understand is why my original command was not working as expected. Is it a bug in Opensearch?

According to the documentation, $0 should be replaced with the original index name. So I don’t understand what is wrong with my original command?

It could be due to a bug or an implementation quirk in Elasticsearch/OpenSearch.

I’m hitting this situation in 2026, and I’m using match groups and $1.

What I’ve found is that it repeats the replacement (but without the match groups) when there’s only one replacement.

So:

{
  "rename_pattern": "(.*)",
  "rename_replacement": "restored-$1-index",
  ...
}

Gives restored-<index_name>-indexrestored--index

But:

{
  "rename_pattern": "(.)(.*)",
  "rename_replacement": "restored-$1$2-index",
  ...
}

Gives the expected restored-<index_name>-index, because it matches the first character and then the rest of the characters.

I don’t know why it would do that. But the behaviour is consistent. One variable in the replacement: duplicated text. Two ore more variables: works as expected.

@StuartBertramTXP What is your OS version?

Looks like we’re still using 2.19 on AWS. I believe we updated as far as we could about a year ago, when the big EOL wave was coming for various hosted versions.

It looks like there’s 3.x versions available now. Is this something that’s fixed in 3.x, then?

@StuartBertramTXP As you’ve already noticed, the observed incorrect restored index name is caused by the rename_pattern.

When you use * in the pattern, it matches 0 or more characters. Because .* can also match an empty string, the replacement is applied twice:

  • security-auditlog-2026.08.19
  • an empty string at the end of the index name

This will result in restored-security-auditlog-2026.08.19-indexrestored--index.
Instead, use + in rename_pattern. + means 1 or more characters, so it won’t match an empty string.

{
  "rename_pattern": "(.+)",
  "rename_replacement": "restored-$1-index",
  ...
}

This will produce restored-security-auditlog-2026.08.19-index.
It is not a bug, but expected regular expression behaviour.

@pablo Thanks for the explanation. I guess that makes some sense. But I’ve somehow managed to miss that behaviour of replacement in 20+ years of programming!

.* is a greedy operator, so I expect it to match any string of any length. Which is the full string. And then it’s done. It matched its input. Nothing else to do. But I’ve just checked in two different languages and they both show the same behaviour of matching the empty string at the end. Interestingly, sed does not and behaves as I originally expected (presumably because it’s a stream editor and so the context is slightly different)

At least we’ve got this three and a half year old oddity cleared up!

@StuartBertramTXP Great to hear that it helped. :tada: