diff --git a/src/OpenTelemetry.Extensions/CHANGELOG.md b/src/OpenTelemetry.Extensions/CHANGELOG.md
index cb4b96a8c2..c6a8780f8c 100644
--- a/src/OpenTelemetry.Extensions/CHANGELOG.md
+++ b/src/OpenTelemetry.Extensions/CHANGELOG.md
@@ -5,6 +5,9 @@
* Updated OpenTelemetry core component version(s) to `1.15.2`.
([#4080](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4080))
+* Fixed `RateLimitingSampler` to reject non-positive `maxTracesPerSecond` values.
+ ([#4127](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4127))
+
## 1.14.0-beta.1
Released 2025-Nov-13
diff --git a/src/OpenTelemetry.Extensions/Trace/RateLimitingSampler.cs b/src/OpenTelemetry.Extensions/Trace/RateLimitingSampler.cs
index 341ffcacad..a213b24bf6 100644
--- a/src/OpenTelemetry.Extensions/Trace/RateLimitingSampler.cs
+++ b/src/OpenTelemetry.Extensions/Trace/RateLimitingSampler.cs
@@ -28,6 +28,11 @@ public class RateLimitingSampler : Sampler
/// The maximum number of traces that will be emitted each second.
public RateLimitingSampler(int maxTracesPerSecond)
{
+ if (maxTracesPerSecond <= 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(maxTracesPerSecond), maxTracesPerSecond, "Value must be greater than zero.");
+ }
+
var maxBalance = maxTracesPerSecond < 1.0 ? 1.0 : maxTracesPerSecond;
this.rateLimiter = new RateLimiter(maxTracesPerSecond, maxBalance);
var attributes = new Dictionary()
diff --git a/test/OpenTelemetry.Extensions.Tests/Trace/RateLimitingSamplerTests.cs b/test/OpenTelemetry.Extensions.Tests/Trace/RateLimitingSamplerTests.cs
index 29ed32220a..29f190ea23 100644
--- a/test/OpenTelemetry.Extensions.Tests/Trace/RateLimitingSamplerTests.cs
+++ b/test/OpenTelemetry.Extensions.Tests/Trace/RateLimitingSamplerTests.cs
@@ -8,6 +8,16 @@ namespace OpenTelemetry.Extensions.Tests.Trace;
public class RateLimitingSamplerTests
{
+ [Theory]
+ [InlineData(0)]
+ [InlineData(-1)]
+ public void Constructor_ThrowsArgumentOutOfRangeException_WhenMaxTracesPerSecondIsNotPositive(int maxTracesPerSecond)
+ {
+ var exception = Assert.Throws(() => new RateLimitingSampler(maxTracesPerSecond));
+
+ Assert.Equal("maxTracesPerSecond", exception.ParamName);
+ }
+
[Fact]
public void ShouldSample_ReturnsRecordAndSample_WhenWithinRateLimit()
{