Skip to content

serve s3: HeadObject/GetObject return upload time as Last-Modified after PutObject #10128

Closed

Description

@johnsonstack

What is the problem you are having with rclone?

After an object is uploaded with PutObject, HeadObject and GetObject return the upload time as Last-Modified instead of the object's modification time, until the metadata cache entry is evicted (by default only after 100000 newer objects or a restart). ListObjects returns the correct modification time, so a client sees two different times for the same object.

Cause: gofakes3 metadataHeaders() adds meta["Last-Modified"] = formatHeaderTime(now) to the request metadata. storeMeta() in cmd/serve/s3/backend.go stores that map in the metadata cache, and HeadObject/GetObject build meta with "Last-Modified": formatHeaderTime(node.ModTime()) and then maps.Copy(meta, metaMap), which overwrites it with the cached upload time. This happens even when X-Amz-Meta-Mtime set the object's modification time to something else.

Real-world effect: Remotely Save (Obsidian) records the Last-Modified from HeadObject right after an upload. When the user later deletes or renames that file on the device, the plugin compares the listing time with the recorded one, decides the remote file changed, and downloads it again instead of deleting it. Deletions of files uploaded from the device never take effect.

What is your rclone version (output from rclone version)

rclone v1.76.0-beta.10592.35a03a47e (docker image rclone/rclone:sha-35a03a4). The same happens with v1.75.1.

Which OS you are using and how many bits (e.g. Windows 7, 64 bit)

Linux amd64 (Docker, Alpine image), Ubuntu 24.04 host.

Which cloud storage system are you using? (e.g. Google Drive)

Google Drive behind a combine remote, served with rclone serve s3.

The command you were trying to run (e.g. rclone copy /tmp remote:tmp)

rclone serve s3 vault-combine: --addr :8080 --vfs-cache-mode writes --cache-dir /cache \
  --dir-cache-time 168h --poll-interval 15s --vfs-refresh

Reproduce with any S3 client:

touch -d "2021-06-06 06:06:06" leer.md
rclone copyto leer.md s3:bucket/leer.md
rclone lsl --use-server-modtime s3:bucket/leer.md                        # 2021-06-06 06:06:06 (correct, from ListObjects)
rclone lsl --use-server-modtime --dump headers s3:bucket/leer.md | grep -i last-modified
Last-Modified: Sun, 18 Oct 2026 18:52:20 GMT                             # upload time (wrong)

Suggested fix

Drop the gofakes3 upload time before caching:

func (t *tenant) storeMeta(_vfs *vfs.VFS, fp string, meta map[string]string) (err error) {
	delete(meta, "Last-Modified")
	...

With this change HeadObject/GetObject return the object's modification time right after the upload (tested against the same Google Drive backend: HEAD/GET right after PUT now return the X-Amz-Meta-Mtime time, deletes from the client propagate), and the Remotely Save delete/rename case works.

A log from the command with the -vv flag

Not needed; the behaviour is visible in the response headers above.

How to use GitHub

  • Please use the 👍 reaction to show that you are affected by the same issue.

Activity

  1. alan16742 commented on Oct 20, 2026

    @alan16742

    same situation, using the local storage backend, the current mitigation uses '--dir-cache-time 10ms', but this may consume more resources for other storage

  2. ncw commented on Oct 20, 2026

    @ncw
    Member

    I've merged @kevin9327 fix for this to master now which means it will be in the latest beta in 15-30 minutes and released in v1.76

  3. added a commit that references this issue on Oct 20, 2026
    81e7372
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions