I don't think this is an Rclone specific issue after looking into it more, but rather a GCS one.
Here is a relevant issue from stack overflow:
Why does gsutil cp require storage.objects.delete on versioned bucket? - Stack Overflow
Thanks for the additional command line (--dump headers). That let me see what was actually happening.
The logs below (with redacted information) from rclone copy clearly show it is executing the POST command to GCS to start the upload and that causes google to send back the 403 error code.
Therefore, it is a counter-intuitive thing that overwriting a file requires "delete" permission in GCS and there is no way to build a service account that can "update" but not "delete" objects in GCS.
Thanks for the assist to get the to the bottom of the issue!
2021/09/27 17:40:09 DEBUG : rclone: Version "v1.56.0" starting with parameters ["rclone" "-vv" "--dump" "headers" "copy" "hi.txt" "gcs-updater:/<bucket>/<directory>/hi.txt"]
2021/09/27 17:40:09 DEBUG : Creating backend with remote "hi.txt"
2021/09/27 17:40:09 DEBUG : Using config file from "/root/.config/rclone/rclone.conf"
2021/09/27 17:40:09 DEBUG : fs cache: adding new entry for parent of "hi.txt", "/root"
2021/09/27 17:40:09 DEBUG : Creating backend with remote "gcs-updater:/<bucket>/<directory>/hi.txt"
2021/09/27 17:40:09 DEBUG : You have specified to dump information. Please be noted that the Accept-Encoding as shown may not be correct in the request and the response may not show Content-Encoding if the go standard libraries auto gzip encoding was in effect. In this case the body of the request will be gunzipped before showing it.
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : HTTP REQUEST (req 0xc00064dd00)
2021/09/27 17:40:09 DEBUG : POST /token HTTP/1.1
Host: oauth2.googleapis.com
User-Agent: rclone/v1.56.0
Content-Length: 795
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : HTTP RESPONSE (req 0xc00064dd00)
2021/09/27 17:40:09 DEBUG : HTTP/2.0 200 OK
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: private
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Sep 2021 17:40:06 GMT
Server: scaffolding on HTTPServer2
Vary: Origin
Vary: X-Origin
Vary: Referer
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 0
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : HTTP REQUEST (req 0xc000708300)
2021/09/27 17:40:09 DEBUG : GET /storage/v1/b/<bucket>/o/<directory>%2Fhi.txt?alt=json&prettyPrint=false HTTP/1.1
Host: storage.googleapis.com
User-Agent: rclone/v1.56.0
Authorization: XXXX
X-Goog-Api-Client: gl-go/1.16.6 gdcl/20210406
Accept-Encoding: gzip
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : HTTP RESPONSE (req 0xc000708300)
2021/09/27 17:40:09 DEBUG : HTTP/2.0 404 Not Found
Content-Length: 279
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Sep 2021 17:40:06 GMT
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Server: UploadServer
Vary: Origin
Vary: X-Origin
X-Guploader-Uploadid: <redacted>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : fs cache: renaming cache item "gcs-updater:/<bucket>/<directory>/hi.txt" to be canonical "gcs-updater:<bucket>/<directory>/hi.txt"
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : HTTP REQUEST (req 0xc000199500)
2021/09/27 17:40:09 DEBUG : GET /storage/v1/b/<bucket>/o/<directory>%2Fhi.txt%2Fhi.txt?alt=json&prettyPrint=false HTTP/1.1
Host: storage.googleapis.com
User-Agent: rclone/v1.56.0
Authorization: XXXX
X-Goog-Api-Client: gl-go/1.16.6 gdcl/20210406
Accept-Encoding: gzip
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : HTTP RESPONSE (req 0xc000199500)
2021/09/27 17:40:09 DEBUG : HTTP/2.0 200 OK
Content-Length: 1000
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: private, max-age=0, must-revalidate, no-transform
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Sep 2021 17:40:06 GMT
Etag: COOVqYXYn/MCEAE=
Expires: Mon, 27 Sep 2021 17:40:06 GMT
Server: UploadServer
Vary: Origin
Vary: X-Origin
X-Guploader-Uploadid: <redacted>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : hi.txt: Sizes differ (src 5 vs dst 3)
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : HTTP REQUEST (req 0xc000199d00)
2021/09/27 17:40:09 DEBUG : GET /storage/v1/b/<bucket>/o?alt=json&maxResults=1&prettyPrint=false HTTP/1.1
Host: storage.googleapis.com
User-Agent: rclone/v1.56.0
Authorization: XXXX
X-Goog-Api-Client: gl-go/1.16.6 gdcl/20210406
Accept-Encoding: gzip
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : HTTP RESPONSE (req 0xc000199d00)
2021/09/27 17:40:09 DEBUG : HTTP/2.0 200 OK
Content-Length: 1037
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: private, max-age=0, must-revalidate, no-transform
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Sep 2021 17:40:07 GMT
Expires: Mon, 27 Sep 2021 17:40:07 GMT
Server: UploadServer
Vary: Origin
Vary: X-Origin
X-Guploader-Uploadid: <redacted>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : HTTP REQUEST (req 0xc0002b7800)
2021/09/27 17:40:09 DEBUG : POST /upload/storage/v1/b/<bucket>/o?alt=json&name=<directory>%2Fhi.txt%2Fhi.txt&prettyPrint=false&uploadType=multipart HTTP/1.1
Host: storage.googleapis.com
User-Agent: rclone/v1.56.0
Transfer-Encoding: chunked
Authorization: XXXX
Content-Type: multipart/related; boundary=80d31d8620982f8345626a0ef4e1e41f98ff371706a6928cc23c04fa1318
X-Goog-Api-Client: gl-go/1.16.6 gdcl/20210406
Accept-Encoding: gzip
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : HTTP RESPONSE (req 0xc0002b7800)
2021/09/27 17:40:09 DEBUG : HTTP/2.0 403 Forbidden
Content-Length: 366
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Sep 2021 17:40:07 GMT
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Server: UploadServer
Vary: Origin
Vary: X-Origin
X-Guploader-Uploadid: <redacted>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 ERROR : hi.txt: Failed to copy: googleapi: Error 403: rclone-updater@<projectid>.iam.gserviceaccount.com does not have storage.objects.delete access to the Google Cloud Storage object., forbidden
2021/09/27 17:40:09 ERROR : Attempt 1/3 failed with 1 errors and: googleapi: Error 403: rclone-updater@<projectid>.iam.gserviceaccount.com does not have storage.objects.delete access to the Google Cloud Storage object., forbidden
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : HTTP REQUEST (req 0xc000708700)
2021/09/27 17:40:09 DEBUG : GET /storage/v1/b/<bucket>/o/<directory>%2Fhi.txt%2Fhi.txt?alt=json&prettyPrint=false HTTP/1.1
Host: storage.googleapis.com
User-Agent: rclone/v1.56.0
Authorization: XXXX
X-Goog-Api-Client: gl-go/1.16.6 gdcl/20210406
Accept-Encoding: gzip
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : HTTP RESPONSE (req 0xc000708700)
2021/09/27 17:40:09 DEBUG : HTTP/2.0 200 OK
Content-Length: 1000
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: private, max-age=0, must-revalidate, no-transform
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Sep 2021 17:40:07 GMT
Etag: COOVqYXYn/MCEAE=
Expires: Mon, 27 Sep 2021 17:40:07 GMT
Server: UploadServer
Vary: Origin
Vary: X-Origin
X-Guploader-Uploadid: <redacted>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : hi.txt: Sizes differ (src 5 vs dst 3)
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : HTTP REQUEST (req 0xc000708c00)
2021/09/27 17:40:09 DEBUG : POST /upload/storage/v1/b/<bucket>/o?alt=json&name=<directory>%2Fhi.txt%2Fhi.txt&prettyPrint=false&uploadType=multipart HTTP/1.1
Host: storage.googleapis.com
User-Agent: rclone/v1.56.0
Transfer-Encoding: chunked
Authorization: XXXX
Content-Type: multipart/related; boundary=59796b6ca9b43b1ed26b6360862b9a35d65dd17b9a5c7c1ccb9a1afe0bf5
X-Goog-Api-Client: gl-go/1.16.6 gdcl/20210406
Accept-Encoding: gzip
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : HTTP RESPONSE (req 0xc000708c00)
2021/09/27 17:40:09 DEBUG : HTTP/2.0 403 Forbidden
Content-Length: 366
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Sep 2021 17:40:07 GMT
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Server: UploadServer
Vary: Origin
Vary: X-Origin
X-Guploader-Uploadid: <redacted>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 ERROR : hi.txt: Failed to copy: googleapi: Error 403: rclone-updater@<projectid>.iam.gserviceaccount.com does not have storage.objects.delete access to the Google Cloud Storage object., forbidden
2021/09/27 17:40:09 ERROR : Attempt 2/3 failed with 1 errors and: googleapi: Error 403: rclone-updater@<projectid>.iam.gserviceaccount.com does not have storage.objects.delete access to the Google Cloud Storage object., forbidden
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : HTTP REQUEST (req 0xc000709100)
2021/09/27 17:40:09 DEBUG : GET /storage/v1/b/<bucket>/o/<directory>%2Fhi.txt%2Fhi.txt?alt=json&prettyPrint=false HTTP/1.1
Host: storage.googleapis.com
User-Agent: rclone/v1.56.0
Authorization: XXXX
X-Goog-Api-Client: gl-go/1.16.6 gdcl/20210406
Accept-Encoding: gzip
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : HTTP RESPONSE (req 0xc000709100)
2021/09/27 17:40:09 DEBUG : HTTP/2.0 200 OK
Content-Length: 1000
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: private, max-age=0, must-revalidate, no-transform
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Sep 2021 17:40:07 GMT
Etag: COOVqYXYn/MCEAE=
Expires: Mon, 27 Sep 2021 17:40:07 GMT
Server: UploadServer
Vary: Origin
Vary: X-Origin
X-Guploader-Uploadid: <redacted>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : hi.txt: Sizes differ (src 5 vs dst 3)
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : HTTP REQUEST (req 0xc00064dc00)
2021/09/27 17:40:09 DEBUG : POST /upload/storage/v1/b/<bucket>/o?alt=json&name=<directory>%2Fhi.txt%2Fhi.txt&prettyPrint=false&uploadType=multipart HTTP/1.1
Host: storage.googleapis.com
User-Agent: rclone/v1.56.0
Transfer-Encoding: chunked
Authorization: XXXX
Content-Type: multipart/related; boundary=6c7356bc76ff8b64c5d9799088deace9335d41106806b8ad0d7bea9ffc54
X-Goog-Api-Client: gl-go/1.16.6 gdcl/20210406
Accept-Encoding: gzip
2021/09/27 17:40:09 DEBUG : >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 DEBUG : HTTP RESPONSE (req 0xc00064dc00)
2021/09/27 17:40:09 DEBUG : HTTP/2.0 403 Forbidden
Content-Length: 366
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Sep 2021 17:40:07 GMT
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Server: UploadServer
Vary: Origin
Vary: X-Origin
X-Guploader-Uploadid: <redacted>
2021/09/27 17:40:09 DEBUG : <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2021/09/27 17:40:09 ERROR : hi.txt: Failed to copy: googleapi: Error 403: rclone-updater@<projectid>.iam.gserviceaccount.com does not have storage.objects.delete access to the Google Cloud Storage object., forbidden
2021/09/27 17:40:09 ERROR : Attempt 3/3 failed with 1 errors and: googleapi: Error 403: rclone-updater@<projectid>.iam.gserviceaccount.com does not have storage.objects.delete access to the Google Cloud Storage object., forbidden
2021/09/27 17:40:09 INFO :
Transferred: 15 / 15 Byte, 100%, 0 Byte/s, ETA -
Errors: 1 (retrying may help)
Elapsed time: 0.5s
2021/09/27 17:40:09 DEBUG : 5 go routines active
2021/09/27 17:40:09 Failed to copy: googleapi: Error 403: rclone-updater@<projectid>.iam.gserviceaccount.com does not have storage.objects.delete access to the Google Cloud Storage object., forbidden