What is the problem you are having with rclone ?
I am using an rclone union remote over multiple independent Hetzner Storage Boxes accessed through SFTP.
The union is configured with :
action_policy = epall
create_policy = mfs
search_policy = ff
When the same logical file already physically exists on multiple union upstreams, I expect action_policy = epall to update all existing copies.
However, with current rclone versions and the default atomic .partial upload mechanism, only one physical copy is updated. The other existing copies remain unchanged.
The problem is reproducible with two SFTP upstreams.
For example, before the update :
H: file.bin = 65536 bytes
H1: file.bin = 65536 bytes
After updating the file through the union without --inplace :
H: file.bin = 131072 bytes
H1: file.bin = 65536 bytes
The debug log shows that rclone creates a temporary file :
file.bin.<hash>.partial
The temporary path does not exist on either upstream, so the union appears to process it using the create_policy.
Because create_policy = mfs, the temporary file is created on only one upstream. It is then renamed to the final filename on that upstream only.
The other existing physical copy is therefore not updated, even though action_policy = epall is configured.
The same test works correctly when I add --inplace :
H: file.bin = 131072 bytes
H1: file.bin = 131072 bytes
It also works correctly with an older rclone v1.60.1-DEV executable, before atomic SFTP .partial uploads were enabled by default.
Deleting a duplicated object through the union also correctly removes the object from both upstreams, so epall is active for deletion.
I have also tested the creation of new files:
-
64 files with rclone v1.74.4 and 8 parallel transfers
-
128 files with the preserved v1.60.1-DEV executable and 8 parallel transfers
No duplicate was created in either test. Each source file resulted in exactly one physical destination file.
Therefore, I cannot currently prove that rclone created the initial duplicate files in my production storage.
However, I can reproduce that once duplicate physical copies exist, current atomic .partial uploads can update only one copy and leave the other copies stale.
In my production environment, a read-only audit across 12 SFTP upstreams found :
Duplicate logical path groups: 8083
Extra physical copies: 31513
Groups with identical sizes: 6314
Groups with different sizes: 1769
Minimum additional storage used by identical-size copies:
20946004960021 bytes
The union and crypt views only expose one copy because search_policy = ff.
No .zfs paths were found in the decrypted destination during the current audit, so these physical duplicate paths are not explained by .zfs/snapshot entries.
My questions are :
-
Is this behavior expected when atomic
.partialuploads are used with a union remote ? -
Should
action_policy = epallreplace all existing copies of the final object ? -
Is
--inplacecurrently required to preserveepallupdate semantics ? -
Should the union backend disable or specially handle
PartialUploadswhen the action policy selects multiple upstreams ? -
Could this behavior explain why duplicated physical copies gradually develop different sizes or contents ?
Run the command 'rclone version' and share the full output of the command.
rclone v1.74.4
- os/version: ubuntu 24.04 (64 bit)
- os/kernel: 6.8.0-134-generic (x86_64)
- os/type: linux
- os/arch: amd64
- go/version: go1.26.5
- go/linking: static
- go/tags: none
I also performed a comparison with the exact older executable previously used by my production sync :
rclone v1.60.1-DEV
- os/version: ubuntu 24.04 (64 bit)
- os/kernel: 6.8.0-134-generic (x86_64)
- os/type: linux
- os/arch: amd64
- go/version: go1.22.2
- go/linking: dynamic
- go/tags: none
SHA-256 of the preserved old executable :
71e94910f24d82f7ef3aefe39bb4df757e7a865712ebea6cf15b5b805ce1cc27
Which cloud storage system are you using ?
Hetzner Storage Boxes accessed through the rclone SFTP backend.
The production architecture is :
12 independent Hetzner Storage Boxes -> rclone union -> rclone crypt
The reproduction uses two independent Hetzner Storage Boxes:
H = SFTP Storage Box
H1 = SFTP Storage Box
The command you were trying to run
First, I created an identical file directly on both upstreams :
dd if=/dev/urandom \
of=/tmp/epall-test.bin \
bs=64K \
count=1 \
status=none
rclone copyto \
/tmp/epall-test.bin \
H:_rclone_union_probe/epall-test/file.bin
rclone copyto \
/tmp/epall-test.bin \
H1:_rclone_union_probe/epall-test/file.bin
Both physical files initially had the same size :
H: 65536 file.bin
H1: 65536 file.bin
I then replaced the local file with a larger file :
dd if=/dev/urandom \
of=/tmp/epall-test.bin \
bs=128K \
count=1 \
status=none
Command reproducing the issue :
rclone copyto \
/tmp/epall-test.bin \
UnionDuplicateProbe:epall-test/file.bin \
-vv \
--log-file /root/union-probe-epall-update.log
Result :
H: 131072 file.bin
H1: 65536 file.bin
Control test with --inplace :
rclone copyto \
/tmp/epall-test.bin \
UnionDuplicateProbe:epall-test/file.bin \
--inplace \
-vv \
--log-file /root/union-probe-epall-inplace.log
Result :
H: 131072 file.bin
H1: 131072 file.bin
Control test with rclone v1.60.1-DEV :
/root/rclone-v1.60.1-DEV copyto \
/tmp/epall-old.bin \
UnionDuplicateProbe:epall-old/file.bin \
-vv \
--log-file /root/union-probe-epall-old-update.log
Before this test, both upstream copies were 65536 bytes.
Result after the update :
H: 196608 file.bin
H1: 196608 file.bin
Delete control test :
rclone deletefile \
UnionDuplicateProbe:delete-test/file.bin \
-vv \
--log-file /root/union-probe-epall-delete.log
The file was removed from both H and H1.
The rclone config contents with secrets removed.
[H]
type = sftp
host = XXX
user = XXX
port = 23
pass = XXX
shell_type = unix
md5sum_command = md5 -r
sha1sum_command = sha1 -r
[H1]
type = sftp
host = XXX
user = XXX
port = 23
pass = XXX
shell_type = unix
md5sum_command = md5 -r
sha1sum_command = sha1 -r
[UnionDuplicateProbe]
type = union
cache_time = 120
upstreams = H:_rclone_union_probe H1:_rclone_union_probe
action_policy = epall
create_policy = mfs
search_policy = ff
Production union and crypt configuration :
[HetznerUnion]
type = union
upstreams = H11:PMSNew H10:PMSNew H9:PMSNew H8:PMSNew H7:PMSNew H6:PMSNew H5:PMSNew H4:PMSNew H3:PMSNew H2:PMSNew H1:PMSNew H:PMSNew
create_policy = mfs
[HetznerCloud]
type = crypt
remote = HetznerUnion:
password = XXX
filename_encoding = base32768
The production union uses the default values for the policies that are not explicitly present :
action_policy = epall
search_policy = ff
A log from the command with the -vv flag
Relevant extract from the update without --inplace :
2026/07/20 13:22:31 DEBUG : rclone: Version "v1.74.4" starting with parameters ["rclone" "copyto" "/tmp/rclone-union-probe-batch/file-01.bin" "UnionDuplicateProbe:batch/file-01.bin" "-vv" "--log-file" "/root/union-probe-epall-update.log"]
2026/07/20 13:22:31 DEBUG : Creating backend with remote "UnionDuplicateProbe:batch/"
2026/07/20 13:22:31 DEBUG : Creating backend with remote "H1:_rclone_union_probe"
2026/07/20 13:22:31 DEBUG : Creating backend with remote "H:_rclone_union_probe"
2026/07/20 13:22:32 DEBUG : union root 'batch': actionPolicy = *policy.EpAll, createPolicy = *policy.Mfs, searchPolicy = *policy.FF
2026/07/20 13:22:32 DEBUG : file-01.bin: size = 131072 (Local file system at /tmp/rclone-union-probe-batch)
2026/07/20 13:22:32 DEBUG : file-01.bin: size = 65536 (union root 'batch')
2026/07/20 13:22:32 DEBUG : file-01.bin: Sizes differ
2026/07/20 13:22:32 DEBUG : file-01.bin.627753be.partial: size = 131072 OK
2026/07/20 13:22:32 DEBUG : sftp://USER@HOST:23/_rclone_union_probe/batch: Shell path "/home/_rclone_union_probe/batch/file-01.bin.627753be.partial"
2026/07/20 13:22:33 DEBUG : file-01.bin.627753be.partial: renamed to: file-01.bin
2026/07/20 13:22:33 INFO : file-01.bin: Copied (replaced existing)
Transferred: 128 KiB / 128 KiB, 100%
Transferred: 1 / 1, 100%
Elapsed time: 0.5s
Relevant extract from the successful test with --inplace :
2026/07/20 13:38:14 DEBUG : rclone: Version "v1.74.4" starting with parameters ["rclone" "copyto" "/tmp/epall-inplace.bin" "UnionDuplicateProbe:epall-inplace/file.bin" "--inplace" "-vv" "--log-file" "/root/union-probe-epall-inplace.log"]
2026/07/20 13:38:15 DEBUG : union root 'epall-inplace': actionPolicy = *policy.EpAll, createPolicy = *policy.Mfs, searchPolicy = *policy.FF
2026/07/20 13:38:15 DEBUG : file.bin: size = 65536 (union root 'epall-inplace')
2026/07/20 13:38:15 DEBUG : file.bin: size = 131072 OK
2026/07/20 13:38:15 INFO : epall-inplace.bin: Copied (replaced existing) to: file.bin
Physical result after the --inplace test :
H:
131072 2026-07-20 13:38:13 file.bin
H1:
131072 2026-07-20 13:38:13 file.bin
Relevant extract from the successful test with rclone v1.60.1-DEV :
2026/07/20 13:38:43 DEBUG : rclone: Version "v1.60.1-DEV" starting with parameters ["/root/rclone-v1.60.1-DEV" "copyto" "/tmp/epall-old.bin" "UnionDuplicateProbe:epall-old/file.bin" "-vv" "--log-file" "/root/union-probe-epall-old-update.log"]
2026/07/20 13:38:45 DEBUG : union root 'epall-old': actionPolicy = *policy.EpAll, createPolicy = *policy.Mfs, searchPolicy = *policy.FF
2026/07/20 13:38:45 INFO : epall-old.bin: Copied (replaced existing) to: file.bin
Physical result :
H:
196608 2026-07-20 13:38:43 file.bin
H1:
196608 2026-07-20 13:38:43 file.bin
I can provide the complete anonymized logs if required.
Thanks.