hel_Sinki
(hel Sinki)
2 april 2026 om 05:07
1
Priority/Severity:
High for self-hosted instances using S3-compatible backup storage, because scheduled backups fail after archive creation.
Platform:
Self-hosted Discourse on latest branch.
Current live version when observed: v2026.4.0-latest
Ruby: 3.4.0
aws-sdk-s3: 1.182.0
Description:
Backups to Cloudflare R2 fail at the final “Uploading archive…” step.
The database dump and local archive creation complete successfully, but multipart upload of the finished backup archive fails.
Actual result:
The backup fails with:
EXCEPTION: multipart upload failed: undefined method 'downcase' for nil
Stack trace includes:
aws-sdk-s3-1.182.0/lib/aws-sdk-s3/multipart_file_uploader.rb
lib/backup_restore/s3_backup_store.rb:48
lib/backup_restore/creator.rb:434
Expected result:
The backup archive should upload successfully to the configured S3-compatible backup store.
Reproducible steps:
Configure backup storage to Cloudflare R2 using the S3-compatible backup path.
Use a backup archive larger than the multipart threshold.
Run a manual or scheduled backup.
Observe failure during “Uploading archive…”.
Relevant configuration:
DISCOURSE_BACKUP_LOCATION=s3
DISCOURSE_S3_ENDPOINT=https://.r2.cloudflarestorage.com
DISCOURSE_S3_FORCE_PATH_STYLE=true
DISCOURSE_S3_BACKUP_BUCKET=
AWS_REQUEST_CHECKSUM_CALCULATION=WHEN_REQUIRED
AWS_RESPONSE_CHECKSUM_VALIDATION=WHEN_REQUIRED
Observed stack trace excerpt:
algorithm = resp.context.params[:checksum_algorithm]
k = "checksum_#{algorithm.downcase}".to_sym
This suggests checksum_algorithm is nil in the multipart upload path.
Additional context:
There is a similar recent Meta topic for Backblaze B2:
I’m facing issues with backing up my Discourse instance, the instance is setup to upload to Backblaze’s B2.
Error log:
Making sure archive does not already exist...
Creating empty archive...
Archiving data dump...
Archiving uploads...
Skipping uploads stored on S3.
Removing tmp '/var/www/discourse/tmp/backups/default/2026-01-16-151337' directory...
Gzipping archive, this may take a while...
Uploading archive...
EXCEPTION: failed to abort multipart upload: SSL_read: unexpected eof while reading…
Also, aws-sdk-s3 changelog entries after 1.182.0 appear relevant:
1.201.0: Fix multipart upload to respect request_checksum_calculation when_required mode
1.210.2: Falls back to header request checksums when using custom endpoints or endpoint providers for PutObject and UploadPart operations
Discourse main currently still appears to lock aws-sdk-s3 to 1.182.0:
https://raw.githubusercontent.com/discourse/discourse/main/Gemfile.lock
pfaffman
(Jay Pfaffman)
2 april 2026 om 14:49
2
I haven’t looked at this in a while, but here’s how I’ve dealt with this in the past:
But I did for a site that’s using Backblaze. I created a template I put in /root/aws-revert-template.yml with this:
# This template reverts aws-sdk-s3 to a version that works with backblaze
params:
home: /var/www/discourse
hooks:
after_bundle_exec:
- exec:
cd: $home
cmd:
- bundle config set frozen false
- "sed -i 's/gem \"aws-sdk-s3\", require: false/gem \"aws-sdk-s3\", \"1.177.0\", require: false/' Gemfile"
- bundle update aws-sdk-s3
…
They don’t consider it a bug because they don’t pretend to support every S3-not-so-compatible service on the planet.
I can’t remember just which sites I was doing this for, but I don’t remember changing anything about this recently, so I’m thinking that this is still the “best” workaround.
I think there were some other topics about this when AWS released the new library that broke everyone else’s offerings.
2 likes
hel_Sinki
(hel Sinki)
2 april 2026 om 15:32
3
Thanks, this fixed it for me.
I applied the workaround directly in app.yml via after_bundle_exec, pinned aws-sdk-s3 to 1.177.0 and aws-sdk-core to 3.215, then rebuilt the container. After that, manual backups to Cloudflare R2 succeeded again, and the previously failing browser uploads started working again as well.
In my case the failures were showing up as multipart upload failed: undefined method 'downcase' for nil on aws-sdk-s3 1.182.0.
Appreciate the workaround.
1 like
amiantos
(Brad Root)
4 april 2026 om 07:30
4
Correction… this workaround worked for me too, I just had to put it in its own hooks: block and not add it to an existing hooks block, silly me.