Skip to content

Commit 2c1c8b7

Browse files
sl0thentr0pyclaude
andauthored
feat(transport): Handle HTTP 413 response for oversized envelopes (#2885)
When Relay returns HTTP 413 (Content Too Large), the SDK now logs a specific warning message and records client reports with reason "send_error" for the dropped items. The 413 is not retried since the data is definitively too large. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5685885 commit 2c1c8b7

4 files changed

Lines changed: 88 additions & 1 deletion

File tree

sentry-ruby/lib/sentry/exceptions.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ class Error < StandardError
66

77
class ExternalError < Error
88
end
9+
10+
class SizeExceededError < ExternalError
11+
end
912
end

sentry-ruby/lib/sentry/transport.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ class Transport
1919
:before_send,
2020
:event_processor,
2121
:insufficient_data,
22-
:backpressure
22+
:backpressure,
23+
:send_error
2324
]
2425

2526
include LoggingHelper
@@ -61,6 +62,10 @@ def send_envelope(envelope)
6162
log_debug("[Transport] Sending envelope with items [#{serialized_items.map(&:type).join(', ')}] #{envelope.event_id} to Sentry")
6263
send_data(data)
6364
end
65+
rescue Sentry::SizeExceededError
66+
serialized_items&.each do |item|
67+
record_lost_event(:send_error, item.data_category)
68+
end
6469
end
6570

6671
def serialize_envelope(envelope)

sentry-ruby/lib/sentry/transport/http_transport.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ def send_data(data)
4949

5050
if response.code.match?(/\A2\d{2}/)
5151
handle_rate_limited_response(response) if has_rate_limited_header?(response)
52+
elsif response.code == "413"
53+
error_message = "HTTP 413: Envelope dropped due to exceeded size limit"
54+
error_message += " (body: #{response.body})" if response.body && !response.body.empty?
55+
log_warn(error_message)
56+
57+
raise Sentry::SizeExceededError, error_message
5258
elsif response.code == "429"
5359
log_debug("the server responded with status 429")
5460
handle_rate_limited_response(response)

sentry-ruby/spec/sentry/transport/http_transport_spec.rb

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,79 @@
291291
end
292292

293293
describe "failed request handling" do
294+
context "receive 413 response" do
295+
let(:string_io) { StringIO.new }
296+
297+
before do
298+
configuration.sdk_logger = Logger.new(string_io)
299+
end
300+
301+
context "with response body" do
302+
let(:fake_response) { build_fake_response("413", body: { detail: "Envelope too large" }) }
303+
304+
it "raises SizeExceededError with body in message" do
305+
sentry_stub_request(fake_response)
306+
307+
expect { subject.send_data(data) }.to raise_error(
308+
Sentry::SizeExceededError,
309+
/HTTP 413: Envelope dropped due to exceeded size limit.*body:.*Envelope too large/
310+
)
311+
end
312+
313+
it "logs a warning message with body" do
314+
sentry_stub_request(fake_response)
315+
316+
expect { subject.send_data(data) }.to raise_error(Sentry::SizeExceededError)
317+
expect(string_io.string).to include("HTTP 413: Envelope dropped due to exceeded size limit")
318+
expect(string_io.string).to include("Envelope too large")
319+
end
320+
end
321+
322+
context "with empty response body" do
323+
let(:fake_response) do
324+
Net::HTTPResponse.new("1.0", "413", "").tap do |response|
325+
allow(response).to receive(:body).and_return("")
326+
end
327+
end
328+
329+
it "raises SizeExceededError without body in message" do
330+
sentry_stub_request(fake_response)
331+
332+
expect { subject.send_data(data) }.to raise_error(
333+
Sentry::SizeExceededError,
334+
"HTTP 413: Envelope dropped due to exceeded size limit"
335+
)
336+
end
337+
end
338+
339+
context "records client reports via send_envelope" do
340+
let(:fake_response) { build_fake_response("413", body: { detail: "too large" }) }
341+
342+
it "records send_error for each item in the envelope" do
343+
sentry_stub_request(fake_response)
344+
345+
configuration.send_client_reports = true
346+
transport = Sentry::HTTPTransport.new(configuration)
347+
envelope = transport.envelope_from_event(event)
348+
349+
transport.send_envelope(envelope)
350+
351+
# Should have recorded send_error for the event item
352+
expect(transport.discarded_events[[:send_error, "error"]]).to eq(1)
353+
end
354+
355+
it "does not raise the error to the caller" do
356+
sentry_stub_request(fake_response)
357+
358+
configuration.send_client_reports = true
359+
transport = Sentry::HTTPTransport.new(configuration)
360+
envelope = transport.envelope_from_event(event)
361+
362+
expect { transport.send_envelope(envelope) }.not_to raise_error
363+
end
364+
end
365+
end
366+
294367
context "receive 4xx responses" do
295368
let(:fake_response) { build_fake_response("404") }
296369

0 commit comments

Comments
 (0)