Backups to Cloudflare R2 fail during multipart upload with aws-sdk-s3 1.182.0 (undefined method 'downcase' for nil)

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:

  1. Configure backup storage to Cloudflare R2 using the S3-compatible backup path.
  2. Use a backup archive larger than the multipart threshold.
  3. Run a manual or scheduled backup.
  4. 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:

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

I haven’t looked at this in a while, but here’s how I’ve dealt with this in the past:

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

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

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.