The mtime metadata fallback was nested inside the X-Amz-Meta-Mtime branch, so it only ran when X-Amz-Meta-Mtime was present but invalid - and then set the modtime from the invalid value's failed parse rather than parsing mtime. An object PUT with only mtime metadata kept the upload time as its modtime. Now the two keys are checked independently, as TouchObject already does.