-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Describe the bug
As soon as I upgraded aws-sdk-s3 to 1.178.0 and higher I start to observe the error mentioned in the title.
I think it's related to #3166, where I'm ok with the change itself but I'm having a difficulty to actually migrate and the error I'm getting is rather unique (meaning I hardly find the same error online) so allow me to raise a new issue.
I am using aws-sdk-s3 as the backend for Active Storage 7.2 and "ActiveStorage::IntegrityError" is the abstracted version of the error.
Stacktrace
Aws::S3::Errors::BadDigest: The CRC32 you specified did not match the calculated checksum. (Aws::S3::Errors::BadDigest)
from seahorse/client/plugins/raise_response_errors.rb:17:in 'call'
from aws-sdk-s3/plugins/sse_cpk.rb:24:in 'call'
from aws-sdk-s3/plugins/dualstack.rb:21:in 'call'
from aws-sdk-s3/plugins/accelerate.rb:43:in 'call'
from aws-sdk-core/plugins/checksum_algorithm.rb:169:in 'call'
from aws-sdk-core/plugins/jsonvalue_converter.rb:16:in 'call'
from aws-sdk-core/plugins/invocation_id.rb:16:in 'call'
from aws-sdk-core/plugins/idempotency_token.rb:19:in 'call'
from aws-sdk-core/plugins/param_converter.rb:26:in 'call'
from seahorse/client/plugins/request_callback.rb:89:in 'call'
from aws-sdk-core/plugins/response_paging.rb:12:in 'call'
from seahorse/client/plugins/response_target.rb:24:in 'call'
from aws-sdk-core/plugins/telemetry.rb:39:in 'block in call'
from aws-sdk-core/telemetry/no_op.rb:29:in 'in_span'
from aws-sdk-core/plugins/telemetry.rb:53:in 'span_wrapper'
from aws-sdk-core/plugins/telemetry.rb:39:in 'call'
from seahorse/client/request.rb:72:in 'send_request'
from aws-sdk-s3/client.rb:18639:in 'put_object'
from aws-sdk-s3/object.rb:3082:in 'block in put'
from aws-sdk-core/plugins/user_agent.rb:92:in 'metric'
from aws-sdk-s3/object.rb:3081:in 'put'
from active_storage/service/s3_service.rb:134:in 'upload_with_single_part'
from active_storage/service/s3_service.rb:33:in 'block in upload'
from active_support/notifications.rb:210:in 'block in instrument'
from active_support/notifications/instrumenter.rb:58:in 'instrument'
from active_support/notifications.rb:210:in 'instrument'
from active_storage/service.rb:165:in 'instrument'
from active_storage/service/s3_service.rb:29:in 'upload'
from /home/ac-user/tsunaren/shared/bundle/ruby/3.3.0/gems/activestorage-7.2.2.2/app/models/active_storage/blob.rb:273:in 'upload_without_unfurling'
from active_storage/attached/changes/create_one.rb:26:in 'upload'
from active_support/core_ext/object/try.rb:15:in 'public_send'
from active_support/core_ext/object/try.rb:15:in 'try'
from active_storage/attached/model.rb:142:in 'block in has_one_attached'
from active_support/callbacks.rb:407:in 'instance_exec'
from active_support/callbacks.rb:407:in 'block in make_lambda'
from active_support/callbacks.rb:208:in 'call'
from active_support/callbacks.rb:563:in 'block in invoke_after'
from active_support/callbacks.rb:563:in 'each'
from active_support/callbacks.rb:563:in 'invoke_after'
from active_support/callbacks.rb:111:in 'run_callbacks'
from active_support/callbacks.rb:913:in '_run_commit_callbacks'
from active_record/transactions.rb:385:in 'committed!'
from active_record/connection_adapters/abstract/transaction.rb:307:in 'block in commit_records'
from active_record/connection_adapters/abstract/transaction.rb:344:in 'run_action_on_records'
from active_record/connection_adapters/abstract/transaction.rb:306:in 'commit_records'
from active_record/connection_adapters/abstract/transaction.rb:596:in 'block in commit_transaction'
from active_support/concurrency/null_lock.rb:9:in 'synchronize'
from active_record/connection_adapters/abstract/transaction.rb:584:in 'commit_transaction'
from active_record/connection_adapters/abstract/transaction.rb:628:in 'block in within_new_transaction'
from active_support/concurrency/null_lock.rb:9:in 'synchronize'
from active_record/connection_adapters/abstract/transaction.rb:613:in 'within_new_transaction'
from active_record/connection_adapters/abstract/database_statements.rb:361:in 'transaction'
from active_record/transactions.rb:414:in 'block in with_transaction_returning_status'
from active_record/connection_adapters/abstract/connection_pool.rb:421:in 'with_connection'
from active_record/connection_handling.rb:296:in 'with_connection'
from active_record/transactions.rb:410:in 'with_transaction_returning_status'
from active_record/transactions.rb:362:in 'save'
from active_record/suppressor.rb:52:in 'save'
from active_storage/attached/one.rb:61:in 'attach'
from app/jobs/operator/survey_export_csv_job.rb:31:in 'perform'
from active_job/execution.rb:68:in 'block in _perform_job'
from active_support/callbacks.rb:121:in 'block in run_callbacks'
from i18n.rb:353:in 'with_locale'
from active_job/translation.rb:9:in 'block (2 levels) in <module:Translation>'
from active_support/callbacks.rb:130:in 'instance_exec'
from active_support/callbacks.rb:130:in 'block in run_callbacks'
from active_support/core_ext/time/zones.rb:65:in 'use_zone'
from active_job/timezones.rb:9:in 'block (2 levels) in <module:Timezones>'
from active_support/callbacks.rb:130:in 'instance_exec'
from active_support/callbacks.rb:130:in 'block in run_callbacks'
from active_support/callbacks.rb:141:in 'run_callbacks'
from active_job/execution.rb:67:in '_perform_job'
from active_job/instrumentation.rb:32:in '_perform_job'
from active_job/execution.rb:51:in 'perform_now'
from active_job/instrumentation.rb:26:in 'block in perform_now'
from active_record/railties/job_runtime.rb:13:in 'block in instrument'
from active_job/instrumentation.rb:40:in 'block in instrument'
from active_support/notifications.rb:210:in 'block in instrument'
from active_support/notifications/instrumenter.rb:58:in 'instrument'
from active_support/notifications.rb:210:in 'instrument'
from active_job/instrumentation.rb:39:in 'instrument'
from active_record/railties/job_runtime.rb:11:in 'instrument'
from active_job/instrumentation.rb:26:in 'perform_now'
from active_job/logging.rb:32:in 'block in perform_now'
from active_support/tagged_logging.rb:138:in 'block in tagged'
from active_support/tagged_logging.rb:38:in 'tagged'
from active_support/tagged_logging.rb:138:in 'tagged'
from active_support/broadcast_logger.rb:241:in 'method_missing'
from active_job/logging.rb:39:in 'tag_logger'
from active_job/logging.rb:32:in 'perform_now'
from sentry/rails/active_job.rb:10:in 'perform_now'
from active_job/execution.rb:29:in 'block in execute'
from active_support/callbacks.rb:121:in 'block in run_callbacks'
from active_job/railtie.rb:79:in 'block (4 levels) in <class:Railtie>'
from active_support/reloader.rb:77:in 'block in wrap'
from active_support/execution_wrapper.rb:87:in 'wrap'
from active_support/reloader.rb:74:in 'wrap'
from active_job/railtie.rb:78:in 'block (3 levels) in <class:Railtie>'
from active_support/callbacks.rb:130:in 'instance_exec'
from active_support/callbacks.rb:130:in 'block in run_callbacks'
from active_support/callbacks.rb:141:in 'run_callbacks'
from active_job/execution.rb:27:in 'execute'
from active_job/queue_adapters/sidekiq_adapter.rb:70:in 'perform'
from sidekiq/processor.rb:202:in 'execute_job'
from sidekiq/processor.rb:170:in 'block (2 levels) in process'
from sidekiq/middleware/chain.rb:177:in 'block in invoke'
from sidekiq/history/middleware.rb:54:in 'call'
from sidekiq/middleware/chain.rb:179:in 'block in invoke'
from sentry/sidekiq/sentry_context_middleware.rb:69:in 'call'
from sidekiq/middleware/chain.rb:179:in 'block in invoke'
from sidekiq/failures/middleware.rb:9:in 'call'
from sidekiq/middleware/chain.rb:179:in 'block in invoke'
from sidekiq/middleware/chain.rb:182:in 'invoke'
from sidekiq/processor.rb:169:in 'block in process'
from sidekiq/processor.rb:136:in 'block (6 levels) in dispatch'
from sidekiq/job_retry.rb:113:in 'local'
from sidekiq/processor.rb:135:in 'block (5 levels) in dispatch'
from sidekiq/rails.rb:14:in 'block in call'
from active_support/reloader.rb:77:in 'block in wrap'
from active_support/execution_wrapper.rb:91:in 'wrap'
from active_support/reloader.rb:74:in 'wrap'
from sidekiq/rails.rb:13:in 'call'
from sidekiq/processor.rb:131:in 'block (4 levels) in dispatch'
from sidekiq/processor.rb:263:in 'stats'
from sidekiq/processor.rb:126:in 'block (3 levels) in dispatch'
from sidekiq/job_logger.rb:13:in 'call'
from sidekiq/processor.rb:125:in 'block (2 levels) in dispatch'
from sidekiq/job_retry.rb:80:in 'global'
from sidekiq/processor.rb:124:in 'block in dispatch'
from sidekiq/job_logger.rb:39:in 'prepare'
from sidekiq/processor.rb:123:in 'dispatch'
from sidekiq/processor.rb:168:in 'process'
from sidekiq/processor.rb:78:in 'process_one'
from sidekiq/processor.rb:68:in 'run'
from sidekiq/component.rb:8:in 'watchdog'
from sidekiq/component.rb:17:in 'block in safe_thread'
ActiveStorage::IntegrityError: ActiveStorage::IntegrityError (ActiveStorage::IntegrityError)
from active_storage/service/s3_service.rb:136:in 'rescue in upload_with_single_part'
from active_storage/service/s3_service.rb:133:in 'upload_with_single_part'
from active_storage/service/s3_service.rb:33:in 'block in upload'
from active_support/notifications.rb:210:in 'block in instrument'
from active_support/notifications/instrumenter.rb:58:in 'instrument'
from active_support/notifications.rb:210:in 'instrument'
from active_storage/service.rb:165:in 'instrument'
from active_storage/service/s3_service.rb:29:in 'upload'
from /home/ac-user/tsunaren/shared/bundle/ruby/3.3.0/gems/activestorage-7.2.2.2/app/models/active_storage/blob.rb:273:in 'upload_without_unfurling'
from active_storage/attached/changes/create_one.rb:26:in 'upload'
from active_support/core_ext/object/try.rb:15:in 'public_send'
from active_support/core_ext/object/try.rb:15:in 'try'
from active_storage/attached/model.rb:142:in 'block in has_one_attached'
from active_support/callbacks.rb:407:in 'instance_exec'
from active_support/callbacks.rb:407:in 'block in make_lambda'
from active_support/callbacks.rb:208:in 'call'
from active_support/callbacks.rb:563:in 'block in invoke_after'
from active_support/callbacks.rb:563:in 'each'
from active_support/callbacks.rb:563:in 'invoke_after'
from active_support/callbacks.rb:111:in 'run_callbacks'
from active_support/callbacks.rb:913:in '_run_commit_callbacks'
from active_record/transactions.rb:385:in 'committed!'
from active_record/connection_adapters/abstract/transaction.rb:307:in 'block in commit_records'
from active_record/connection_adapters/abstract/transaction.rb:344:in 'run_action_on_records'
from active_record/connection_adapters/abstract/transaction.rb:306:in 'commit_records'
from active_record/connection_adapters/abstract/transaction.rb:596:in 'block in commit_transaction'
from active_support/concurrency/null_lock.rb:9:in 'synchronize'
from active_record/connection_adapters/abstract/transaction.rb:584:in 'commit_transaction'
from active_record/connection_adapters/abstract/transaction.rb:628:in 'block in within_new_transaction'
from active_support/concurrency/null_lock.rb:9:in 'synchronize'
from active_record/connection_adapters/abstract/transaction.rb:613:in 'within_new_transaction'
from active_record/connection_adapters/abstract/database_statements.rb:361:in 'transaction'
from active_record/transactions.rb:414:in 'block in with_transaction_returning_status'
from active_record/connection_adapters/abstract/connection_pool.rb:421:in 'with_connection'
from active_record/connection_handling.rb:296:in 'with_connection'
from active_record/transactions.rb:410:in 'with_transaction_returning_status'
from active_record/transactions.rb:362:in 'save'
from active_record/suppressor.rb:52:in 'save'
from active_storage/attached/one.rb:61:in 'attach'
from app/jobs/operator/survey_export_csv_job.rb:31:in 'perform'
from active_job/execution.rb:68:in 'block in _perform_job'
from active_support/callbacks.rb:121:in 'block in run_callbacks'
from i18n.rb:353:in 'with_locale'
from active_job/translation.rb:9:in 'block (2 levels) in <module:Translation>'
from active_support/callbacks.rb:130:in 'instance_exec'
from active_support/callbacks.rb:130:in 'block in run_callbacks'
from active_support/core_ext/time/zones.rb:65:in 'use_zone'
from active_job/timezones.rb:9:in 'block (2 levels) in <module:Timezones>'
from active_support/callbacks.rb:130:in 'instance_exec'
from active_support/callbacks.rb:130:in 'block in run_callbacks'
from active_support/callbacks.rb:141:in 'run_callbacks'
from active_job/execution.rb:67:in '_perform_job'
from active_job/instrumentation.rb:32:in '_perform_job'
from active_job/execution.rb:51:in 'perform_now'
from active_job/instrumentation.rb:26:in 'block in perform_now'
from active_record/railties/job_runtime.rb:13:in 'block in instrument'
from active_job/instrumentation.rb:40:in 'block in instrument'
from active_support/notifications.rb:210:in 'block in instrument'
from active_support/notifications/instrumenter.rb:58:in 'instrument'
from active_support/notifications.rb:210:in 'instrument'
from active_job/instrumentation.rb:39:in 'instrument'
from active_record/railties/job_runtime.rb:11:in 'instrument'
from active_job/instrumentation.rb:26:in 'perform_now'
from active_job/logging.rb:32:in 'block in perform_now'
from active_support/tagged_logging.rb:138:in 'block in tagged'
from active_support/tagged_logging.rb:38:in 'tagged'
from active_support/tagged_logging.rb:138:in 'tagged'
from active_support/broadcast_logger.rb:241:in 'method_missing'
from active_job/logging.rb:39:in 'tag_logger'
from active_job/logging.rb:32:in 'perform_now'
from sentry/rails/active_job.rb:10:in 'perform_now'
from active_job/execution.rb:29:in 'block in execute'
from active_support/callbacks.rb:121:in 'block in run_callbacks'
from active_job/railtie.rb:79:in 'block (4 levels) in <class:Railtie>'
from active_support/reloader.rb:77:in 'block in wrap'
from active_support/execution_wrapper.rb:87:in 'wrap'
from active_support/reloader.rb:74:in 'wrap'
from active_job/railtie.rb:78:in 'block (3 levels) in <class:Railtie>'
from active_support/callbacks.rb:130:in 'instance_exec'
from active_support/callbacks.rb:130:in 'block in run_callbacks'
from active_support/callbacks.rb:141:in 'run_callbacks'
from active_job/execution.rb:27:in 'execute'
from active_job/queue_adapters/sidekiq_adapter.rb:70:in 'perform'
from sidekiq/processor.rb:202:in 'execute_job'
from sidekiq/processor.rb:170:in 'block (2 levels) in process'
from sidekiq/middleware/chain.rb:177:in 'block in invoke'
from sidekiq/history/middleware.rb:54:in 'call'
from sidekiq/middleware/chain.rb:179:in 'block in invoke'
from sentry/sidekiq/sentry_context_middleware.rb:69:in 'call'
from sidekiq/middleware/chain.rb:179:in 'block in invoke'
from sidekiq/failures/middleware.rb:9:in 'call'
from sidekiq/middleware/chain.rb:179:in 'block in invoke'
from sidekiq/middleware/chain.rb:182:in 'invoke'
from sidekiq/processor.rb:169:in 'block in process'
from sidekiq/processor.rb:136:in 'block (6 levels) in dispatch'
from sidekiq/job_retry.rb:113:in 'local'
from sidekiq/processor.rb:135:in 'block (5 levels) in dispatch'
from sidekiq/rails.rb:14:in 'block in call'
from active_support/reloader.rb:77:in 'block in wrap'
from active_support/execution_wrapper.rb:91:in 'wrap'
from active_support/reloader.rb:74:in 'wrap'
from sidekiq/rails.rb:13:in 'call'
from sidekiq/processor.rb:131:in 'block (4 levels) in dispatch'
from sidekiq/processor.rb:263:in 'stats'
from sidekiq/processor.rb:126:in 'block (3 levels) in dispatch'
from sidekiq/job_logger.rb:13:in 'call'
from sidekiq/processor.rb:125:in 'block (2 levels) in dispatch'
from sidekiq/job_retry.rb:80:in 'global'
from sidekiq/processor.rb:124:in 'block in dispatch'
from sidekiq/job_logger.rb:39:in 'prepare'
from sidekiq/processor.rb:123:in 'dispatch'
from sidekiq/processor.rb:168:in 'process'
from sidekiq/processor.rb:78:in 'process_one'
from sidekiq/processor.rb:68:in 'run'
from sidekiq/component.rb:8:in 'watchdog'
from sidekiq/component.rb:17:in 'block in safe_thread'
At the level of HTTP request it's a PUT request to https://{bucket}.s3.{region}.amazonaws.com/* resulting in 400 Bad Request, when "The CRC32 you specified did not match the calculated checksum" looks like the error message S3 responds with.
At first I assumed that it is a problem with Active Storage not being ready for the upgrade, but I was not able to reproduce the bad request at all. Below is the script that I thought might reproduce it, but it just works for some reasons.
Details
# frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
gem "rails", "~> 7.2.0"
# If you want to test against edge Rails replace the previous line with this:
# gem "rails", github: "rails/rails", branch: "main"
gem "sqlite3"
gem "aws-sdk-s3", "1.178.0"
end
require "active_record/railtie"
require "active_storage/engine"
require "minitest/autorun"
ENV["DATABASE_URL"] = "sqlite3::memory:"
class TestApp < Rails::Application
config.load_defaults Rails::VERSION::STRING.to_f
config.root = __dir__
config.hosts << "example.org"
config.eager_load = false
config.session_store :cookie_store, key: "cookie_store_key"
config.secret_key_base = "secret_key_base"
config.logger = Logger.new($stdout)
Rails.logger = config.logger
config.active_storage.service = :amazon
config.active_storage.service_configurations = {
amazon: {
service: "S3",
bucket: ENV["AWS_S3_BUCKET"],
region: ENV["AWS_S3_REGION"],
access_key_id: ENV["AWS_ACCESS_KEY_ID"],
secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
}
}
config.active_job.queue_adapter = :inline
end
Rails.application.initialize!
require ActiveStorage::Engine.root.join("db/migrate/20170806125915_create_active_storage_tables.rb").to_s
ActiveRecord::Schema.define do
CreateActiveStorageTables.new.change
create_table :users, force: true
end
class User < ActiveRecord::Base
has_one_attached :profile
end
class BugTest < ActiveSupport::TestCase
def test_upload_and_download
user = User.create!(
profile: {
content_type: "text/plain",
filename: "dummy.txt",
io: ::StringIO.new("dummy"),
}
)
assert_equal "dummy", user.profile.download
end
endConfiguring the client to opt out of the data integrity protections by setting request_checksum_calculation and response_checksum_validation to when_required resolves the issue.
However, disabling the better protection feels like the ultimate decision and it would be great if I can avoid that. But the problem is now that the situation is very unclear so far and I though I should create an issue rather than suffering from it alone.
There are a couple of preceding issues around like these
- Upgrading from aws-sdk-s3 (1.176.1) to aws-sdk-s3 (1.178.0) breaks uploads to Cloudflare R2 #3174
- ActiveStorage creates conflicting checksums when using S3-compatible services on Blob.create_and_upload! rails/rails#54374
Note that both of these issues target Cloudflare R2, while mine targets AWS S3 itself. Also, the exact error message I'm observing which goes like this;
The CRC32 you specified did not match the calculated checksum
and it appears very rarely online, except for this one instance: awslabs/aws-sdk-rust#1240 (comment).
Regression Issue
- Select this option if this issue appears to be a regression.
Expected Behavior
I expect the required actions become clear so I can migrate to the newer default without just turning it off
Current Behavior
The checksum does not match 100% and the mechanism behind it is not so clear. It is unfortunate that I cannot be so sure if it's really inevitable and I can only turn the protection off, or there are actually any actions that I can take and they are only hard to find
Reproduction Steps
Although I have not been able to create a reproduction, the script that I posted above can be a starting point.
Claiming I can observe the error while not being able to reproduce is simply my fault. There should be something somewhere on my side so let me take time to further investigate and hopefully pinpoint, while posting the error and situation as the starting point.
For example, I freshly created a bucket to try to reproduce the issue, while the bucket I can associate the issue with is more than 5 years old. Getting an older bucket to test against is perhaps worth trying.
Sorry for this being a vague assumption. Let me update if things become clearer
Possible Solution
No response
Additional Information/Context
These are dependencies I'm observing the issue with
- ruby 3.3.8
- activestorage 7.2.2.2
- aws-sdk-core 3.239.2
- aws-sdk-s3 1.205.0
- net-http 0.7.0
Gem name ('aws-sdk', 'aws-sdk-resources' or service gems like 'aws-sdk-s3') and its version
aws-sdk-s3 1.178.0 and higher
Environment details (Version of Ruby, OS environment)
Ruby 3.3.8