From 55a7f78ae4483690ec7da9b3684df7af13904ed1 Mon Sep 17 00:00:00 2001 From: Dushyant Acharya Date: Thu, 10 Sep 2026 11:29:25 +0530 Subject: [PATCH 1/3] fix(sdk): add validation for export_timeout_millis <= 0 in BatchSpanProcessor --- .changelog/5648.fixed | 1 + .../opentelemetry/sdk/trace/export/__init__.py | 17 +++++++++++++++-- .../tests/trace/export/test_export.py | 10 ++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 .changelog/5648.fixed diff --git a/.changelog/5648.fixed b/.changelog/5648.fixed new file mode 100644 index 00000000000..085e6f1b66e --- /dev/null +++ b/.changelog/5648.fixed @@ -0,0 +1 @@ +`opentelemetry-sdk`: add validation for export_timeout_millis <= 0 in BatchSpanProcessor diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py index 19a6902bfac..8aad6bbfee3 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py @@ -180,7 +180,12 @@ def __init__( if export_timeout_millis is None: export_timeout_millis = BatchSpanProcessor._default_export_timeout_millis() - BatchSpanProcessor._validate_arguments(max_queue_size, schedule_delay_millis, max_export_batch_size) + BatchSpanProcessor._validate_arguments( + max_queue_size, + schedule_delay_millis, + max_export_batch_size, + export_timeout_millis, + ) self._batch_processor = BatchProcessor( span_exporter, @@ -274,7 +279,12 @@ def _default_export_timeout_millis(): return _DEFAULT_EXPORT_TIMEOUT_MILLIS @staticmethod - def _validate_arguments(max_queue_size, schedule_delay_millis, max_export_batch_size): + def _validate_arguments( + max_queue_size, + schedule_delay_millis, + max_export_batch_size, + export_timeout_millis=None, + ): if max_queue_size <= 0: raise ValueError("max_queue_size must be a positive integer.") @@ -287,6 +297,9 @@ def _validate_arguments(max_queue_size, schedule_delay_millis, max_export_batch_ if max_export_batch_size > max_queue_size: raise ValueError("max_export_batch_size must be less than or equal to max_queue_size.") + if export_timeout_millis is not None and export_timeout_millis <= 0: + raise ValueError("export_timeout_millis must be positive.") + class ConsoleSpanExporter(SpanExporter): """Implementation of :class:`SpanExporter` that prints spans to the diff --git a/opentelemetry-sdk/tests/trace/export/test_export.py b/opentelemetry-sdk/tests/trace/export/test_export.py index c5623dc8e55..bd505d7dacf 100644 --- a/opentelemetry-sdk/tests/trace/export/test_export.py +++ b/opentelemetry-sdk/tests/trace/export/test_export.py @@ -241,6 +241,16 @@ def test_args_env_var(self): self.assertEqual(batch_span_processor._batch_processor._export_timeout_millis, 4) batch_span_processor.shutdown() + def test_invalid_export_timeout_millis(self): + with self.assertRaises(ValueError): + export.BatchSpanProcessor( + MySpanExporter(destination=[]), export_timeout_millis=0 + ) + with self.assertRaises(ValueError): + export.BatchSpanProcessor( + MySpanExporter(destination=[]), export_timeout_millis=-500 + ) + def test_args_env_var_defaults(self): batch_span_processor = export.BatchSpanProcessor(MySpanExporter(destination=[])) From 70e0c15c645ed110c29ea6c41e72940bca705a3c Mon Sep 17 00:00:00 2001 From: Dushyant Acharya Date: Sun, 13 Sep 2026 09:14:50 +0530 Subject: [PATCH 2/3] fix(sdk): add validation for export_timeout_millis in BatchLogRecordProcessor --- .../sdk/_logs/_internal/export/__init__.py | 17 +++++++++++++++-- opentelemetry-sdk/tests/logs/test_export.py | 10 ++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/__init__.py index ea02d8e1fe2..f8c466ddf5a 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/__init__.py @@ -284,7 +284,12 @@ def __init__( if export_timeout_millis is None: export_timeout_millis = BatchLogRecordProcessor._default_export_timeout_millis() - BatchLogRecordProcessor._validate_arguments(max_queue_size, schedule_delay_millis, max_export_batch_size) + BatchLogRecordProcessor._validate_arguments( + max_queue_size, + schedule_delay_millis, + max_export_batch_size, + export_timeout_millis, + ) # Initializes BatchProcessor self._batch_processor = BatchProcessor( exporter, @@ -379,7 +384,12 @@ def _default_export_timeout_millis(): return _DEFAULT_EXPORT_TIMEOUT_MILLIS @staticmethod - def _validate_arguments(max_queue_size, schedule_delay_millis, max_export_batch_size): + def _validate_arguments( + max_queue_size, + schedule_delay_millis, + max_export_batch_size, + export_timeout_millis=None, + ): if max_queue_size <= 0: raise ValueError("max_queue_size must be a positive integer.") @@ -391,3 +401,6 @@ def _validate_arguments(max_queue_size, schedule_delay_millis, max_export_batch_ if max_export_batch_size > max_queue_size: raise ValueError("max_export_batch_size must be less than or equal to max_queue_size.") + + if export_timeout_millis is not None and export_timeout_millis <= 0: + raise ValueError("export_timeout_millis must be positive.") diff --git a/opentelemetry-sdk/tests/logs/test_export.py b/opentelemetry-sdk/tests/logs/test_export.py index 3cfa825d34a..e73105324fc 100644 --- a/opentelemetry-sdk/tests/logs/test_export.py +++ b/opentelemetry-sdk/tests/logs/test_export.py @@ -473,6 +473,16 @@ def test_metrics_already_shutdown(self): # before the end of the test, otherwise the worker thread will continue # to run after the end of the test. class TestBatchLogRecordProcessor(unittest.TestCase): + def test_invalid_export_timeout_millis(self): + with self.assertRaises(ValueError): + BatchLogRecordProcessor( + InMemoryLogRecordExporter(), export_timeout_millis=0 + ) + with self.assertRaises(ValueError): + BatchLogRecordProcessor( + InMemoryLogRecordExporter(), export_timeout_millis=-500 + ) + def test_emit_call_log_record(self): exporter = InMemoryLogRecordExporter() log_record_processor = Mock(wraps=BatchLogRecordProcessor(exporter)) From 2baee8068461751211b2b0dcbb6a6aa050baa0f8 Mon Sep 17 00:00:00 2001 From: Dushyant Acharya Date: Wed, 23 Sep 2026 06:46:36 +0530 Subject: [PATCH 3/3] Rename changelog fragment to match PR number and format test files (#5650) --- .changelog/{5648.fixed => 5650.fixed} | 0 opentelemetry-sdk/tests/logs/test_export.py | 8 ++------ opentelemetry-sdk/tests/trace/export/test_export.py | 8 ++------ 3 files changed, 4 insertions(+), 12 deletions(-) rename .changelog/{5648.fixed => 5650.fixed} (100%) diff --git a/.changelog/5648.fixed b/.changelog/5650.fixed similarity index 100% rename from .changelog/5648.fixed rename to .changelog/5650.fixed diff --git a/opentelemetry-sdk/tests/logs/test_export.py b/opentelemetry-sdk/tests/logs/test_export.py index e73105324fc..f39a8606f96 100644 --- a/opentelemetry-sdk/tests/logs/test_export.py +++ b/opentelemetry-sdk/tests/logs/test_export.py @@ -475,13 +475,9 @@ def test_metrics_already_shutdown(self): class TestBatchLogRecordProcessor(unittest.TestCase): def test_invalid_export_timeout_millis(self): with self.assertRaises(ValueError): - BatchLogRecordProcessor( - InMemoryLogRecordExporter(), export_timeout_millis=0 - ) + BatchLogRecordProcessor(InMemoryLogRecordExporter(), export_timeout_millis=0) with self.assertRaises(ValueError): - BatchLogRecordProcessor( - InMemoryLogRecordExporter(), export_timeout_millis=-500 - ) + BatchLogRecordProcessor(InMemoryLogRecordExporter(), export_timeout_millis=-500) def test_emit_call_log_record(self): exporter = InMemoryLogRecordExporter() diff --git a/opentelemetry-sdk/tests/trace/export/test_export.py b/opentelemetry-sdk/tests/trace/export/test_export.py index bd505d7dacf..e796facd33e 100644 --- a/opentelemetry-sdk/tests/trace/export/test_export.py +++ b/opentelemetry-sdk/tests/trace/export/test_export.py @@ -243,13 +243,9 @@ def test_args_env_var(self): def test_invalid_export_timeout_millis(self): with self.assertRaises(ValueError): - export.BatchSpanProcessor( - MySpanExporter(destination=[]), export_timeout_millis=0 - ) + export.BatchSpanProcessor(MySpanExporter(destination=[]), export_timeout_millis=0) with self.assertRaises(ValueError): - export.BatchSpanProcessor( - MySpanExporter(destination=[]), export_timeout_millis=-500 - ) + export.BatchSpanProcessor(MySpanExporter(destination=[]), export_timeout_millis=-500) def test_args_env_var_defaults(self): batch_span_processor = export.BatchSpanProcessor(MySpanExporter(destination=[]))