diff --git a/src/shared/Angor.Shared.Tests/Services/RelayServiceTests.cs b/src/shared/Angor.Shared.Tests/Services/RelayServiceTests.cs
new file mode 100644
index 000000000..5e660835b
--- /dev/null
+++ b/src/shared/Angor.Shared.Tests/Services/RelayServiceTests.cs
@@ -0,0 +1,59 @@
+using Angor.Shared.Models;
+using Angor.Shared.Services;
+using FluentAssertions;
+
+namespace Angor.Test.Services;
+
+///
+/// Kind 3030 is a draft/custom Nostr kind, not officially reserved, so public relays can contain
+/// unrelated non-JSON content published by other applications under the same kind number.
+/// uses
+/// to cheaply skip that noise (logged at Debug) instead of attempting a full JSON parse that fails
+/// with a JsonException on every such event (previously logged at Warning with a full stack trace).
+///
+public class RelayServiceTests
+{
+ [Fact]
+ public void LooksLikeJsonObject_ReturnsTrue_ForSerializedProjectInfo()
+ {
+ var serializer = new Serializer();
+ var json = serializer.Serialize(new ProjectInfo
+ {
+ FounderKey = "founder",
+ FounderRecoveryKey = "recovery",
+ ProjectIdentifier = "angor1test",
+ NostrPubKey = "abc123",
+ NetworkName = "Testnet"
+ });
+
+ RelayService.LooksLikeJsonObject(json).Should().BeTrue();
+ }
+
+ [Fact]
+ public void LooksLikeJsonObject_ReturnsTrue_WhenContentHasLeadingWhitespace()
+ {
+ RelayService.LooksLikeJsonObject(" \n{\"version\":2}").Should().BeTrue();
+ }
+
+ [Fact]
+ public void LooksLikeJsonObject_ReturnsFalse_ForForeignHexBlobContent()
+ {
+ // Real content observed from an unrelated Nostr event that reused kind 3030 on a public relay
+ // (0x-prefixed hex blob), which previously threw a JsonException at byte position 1.
+ const string foreignContent =
+ "0xdf71595bf0776ae54a15c87844c79d0cff46f6fab1739a084cf04f50d4a700b6dbe5978a67ccfd02451918e5e1747939b8936fef48f37ac439e6d878af7b6de";
+
+ RelayService.LooksLikeJsonObject(foreignContent).Should().BeFalse();
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData("[1,2,3]")]
+ [InlineData("\"just a string\"")]
+ [InlineData("12345")]
+ public void LooksLikeJsonObject_ReturnsFalse_ForNonObjectContent(string content)
+ {
+ RelayService.LooksLikeJsonObject(content).Should().BeFalse();
+ }
+}
diff --git a/src/shared/Angor.Shared/Services/RelayService.cs b/src/shared/Angor.Shared/Services/RelayService.cs
index e0cf50657..937f2e053 100644
--- a/src/shared/Angor.Shared/Services/RelayService.cs
+++ b/src/shared/Angor.Shared/Services/RelayService.cs
@@ -324,6 +324,17 @@ public void LookupLatestProjects(Action> onResponseAction, Actio
if (ev?.Content == null || ev.Id == null)
return;
+ // Kind 3030 is a draft/custom kind, not an officially-reserved Nostr event kind, so
+ // other applications on shared public relays (e.g. relay.damus.io, nos.lol) can and do
+ // reuse the same kind number for unrelated, non-JSON payloads. Skip those quietly
+ // instead of logging a warning for every foreign event; only genuinely JSON-shaped
+ // content that still fails to map to T is worth a warning.
+ if (!LooksLikeJsonObject(ev.Content))
+ {
+ _logger.LogDebug("Skipping non-JSON content for Nostr event {EventId} (kind {Kind} reused by another application)", ev.Id, (int)Nip3030NostrKind);
+ return;
+ }
+
try
{
var projectInfo = _serializer.Deserialize(ev.Content);
@@ -462,6 +473,18 @@ public Task PublishAppSpecificDataAsync(string dTag, string content, str
return Task.FromResult(signed.Id);
}
+ ///
+ /// Cheaply checks whether content is shaped like a JSON object (starts with '{') without
+ /// attempting a full parse. Kind 3030 is not an officially-reserved Nostr event kind, so relays
+ /// can contain unrelated, non-JSON content published by other applications under the same kind
+ /// number; this lets us skip that noise without the cost/verbosity of a failed deserialization.
+ ///
+ internal static bool LooksLikeJsonObject(string content)
+ {
+ var span = content.AsSpan().Trim();
+ return span.Length > 0 && span[0] == '{';
+ }
+
private static NostrEvent GetNip3030NostrEvent(string content, string? projectIdentifier = null)
{
// https://github.com/block-core/nips/blob/peer-to-peer-decentralized-funding/3030.md