diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4082a81567..cc43ec0e83 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
### Fixes
- Fixed ArgumentNullException in FormRequestPayloadExtractor when handling invalid form data on ASP.NET ([#3734](https://github.com/getsentry/sentry-dotnet/pull/3734))
+- Fixed NullReferenceException in SentryTraceHeader when parsing null or empty values ([#3745](https://github.com/getsentry/sentry-dotnet/pull/3745))
### Dependencies
diff --git a/src/Sentry/SentryTraceHeader.cs b/src/Sentry/SentryTraceHeader.cs
index 212deb99bd..ed4d35c372 100644
--- a/src/Sentry/SentryTraceHeader.cs
+++ b/src/Sentry/SentryTraceHeader.cs
@@ -40,10 +40,25 @@ public override string ToString() => IsSampled is { } isSampled
: $"{TraceId}-{SpanId}";
///
- /// Parses from string.
+ /// Parses a from a string representation of the Sentry trace header.
///
- public static SentryTraceHeader Parse(string value)
+ ///
+ /// A string containing the Sentry trace header, expected to follow the format "traceId-spanId-sampled",
+ /// where "sampled" is optional.
+ ///
+ ///
+ /// A object if parsing succeeds, or null if the input string is null, empty, or whitespace.
+ ///
+ ///
+ /// Thrown if the input string does not contain a valid trace header format, specifically if it lacks required trace ID and span ID components.
+ ///
+ public static SentryTraceHeader? Parse(string value)
{
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return null;
+ }
+
var components = value.Split('-', StringSplitOptions.RemoveEmptyEntries);
if (components.Length < 2)
{
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt
index 952c5ab12e..1c60b3fa26 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt
@@ -931,7 +931,7 @@ namespace Sentry
public Sentry.SpanId SpanId { get; }
public Sentry.SentryId TraceId { get; }
public override string ToString() { }
- public static Sentry.SentryTraceHeader Parse(string value) { }
+ public static Sentry.SentryTraceHeader? Parse(string value) { }
}
public class SentryTransaction : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISentryJsonSerializable, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext
{
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt
index 952c5ab12e..1c60b3fa26 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt
@@ -931,7 +931,7 @@ namespace Sentry
public Sentry.SpanId SpanId { get; }
public Sentry.SentryId TraceId { get; }
public override string ToString() { }
- public static Sentry.SentryTraceHeader Parse(string value) { }
+ public static Sentry.SentryTraceHeader? Parse(string value) { }
}
public class SentryTransaction : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISentryJsonSerializable, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext
{
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
index 003fc8ed9a..6cfd7b9964 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
@@ -933,7 +933,7 @@ namespace Sentry
public Sentry.SpanId SpanId { get; }
public Sentry.SentryId TraceId { get; }
public override string ToString() { }
- public static Sentry.SentryTraceHeader Parse(string value) { }
+ public static Sentry.SentryTraceHeader? Parse(string value) { }
}
public class SentryTransaction : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISentryJsonSerializable, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext
{
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
index 5caab10797..5b4ba7b231 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
@@ -928,7 +928,7 @@ namespace Sentry
public Sentry.SpanId SpanId { get; }
public Sentry.SentryId TraceId { get; }
public override string ToString() { }
- public static Sentry.SentryTraceHeader Parse(string value) { }
+ public static Sentry.SentryTraceHeader? Parse(string value) { }
}
public class SentryTransaction : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISentryJsonSerializable, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext
{
diff --git a/test/Sentry.Tests/Protocol/SentryTraceHeaderTests.cs b/test/Sentry.Tests/Protocol/SentryTraceHeaderTests.cs
index 0c8ff348e1..11b46dc58c 100644
--- a/test/Sentry.Tests/Protocol/SentryTraceHeaderTests.cs
+++ b/test/Sentry.Tests/Protocol/SentryTraceHeaderTests.cs
@@ -46,4 +46,17 @@ public void Parse_WithSampledFalse_Works()
header.SpanId.Should().Be(SpanId.Parse("1000000000000000"));
header.IsSampled.Should().BeFalse();
}
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData(" ")]
+ public void Parse_WithoutHeaderValue_ReturnsNull(string headerValue)
+ {
+ // Act
+ var header = SentryTraceHeader.Parse(headerValue);
+
+ // Assert
+ header.Should().BeNull();
+ }
}