JamesNK/Newtonsoft.Json · error · ArgumentException

Object must be of type Uri.

Error message

Object must be of type Uri.

What it means

Thrown by JValue.CompareTo when the token's JSON type is JTokenType.Uri and the operand is not a Uri. Uri JValues compare their underlying string forms with Comparer<string>; an operand that cannot be treated as a Uri is rejected. Note the operand is tested with `as Uri` so derived Uri types are accepted but strings are not.

Source

Thrown at Src/Newtonsoft.Json/Linq/JValue.cs:385

                    byte[]? bytesA = objA as byte[];
                    MiscellaneousUtils.Assert(bytesA != null);

                    return MiscellaneousUtils.ByteArrayCompare(bytesA!, bytesB);
                case JTokenType.Guid:
                    if (!(objB is Guid))
                    {
                        throw new ArgumentException("Object must be of type Guid.");
                    }

                    Guid guid1 = (Guid)objA;
                    Guid guid2 = (Guid)objB;

                    return guid1.CompareTo(guid2);
                case JTokenType.Uri:
                    Uri? uri2 = objB as Uri;
                    if (uri2 == null)
                    {
                        throw new ArgumentException("Object must be of type Uri.");
                    }

                    Uri uri1 = (Uri)objA;

                    return Comparer<string>.Default.Compare(uri1.ToString(), uri2.ToString());
                case JTokenType.TimeSpan:
                    if (!(objB is TimeSpan))
                    {
                        throw new ArgumentException("Object must be of type TimeSpan.");
                    }

                    TimeSpan ts1 = (TimeSpan)objA;
                    TimeSpan ts2 = (TimeSpan)objB;

                    return ts1.CompareTo(ts2);
                default:
                    throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(valueType), valueType, "Unexpected value type: {0}".FormatWith(CultureInfo.InvariantCulture, valueType));
            }

View on GitHub (pinned to 4f73e74372)

Solutions

  1. Wrap the operand in a Uri: token.CompareTo(new Uri(text)).
  2. Compare the string forms directly: ((Uri)token.Value<Uri>()).ToString() == text.
  3. Standardize on a single representation (Uri or string) for URI-typed fields.

Example fix

// before
int c = uriToken.CompareTo("https://example.com");

// after
int c = uriToken.CompareTo(new Uri("https://example.com"));
Defensive patterns

Strategy: type-guard

Validate before calling

if (other is Uri u) { int c = uriToken.CompareTo(u); } else if (other is string s) { int c = uriToken.CompareTo(new Uri(s)); }

Type guard

static bool IsUri(object? o) => o is Uri;

Try / catch

try { int c = token.CompareTo(other); } catch (ArgumentException ex) when (ex.Message.Contains("Uri")) { /* wrap in Uri */ }

Prevention

When it happens

Trigger: Comparing a Uri JValue (created from new JValue(new Uri("https://x"))) against a string literal such as token.CompareTo("https://x"), or against any non-Uri object. Happens during sorting or equality on token collections.

Common situations: Storing URL fields as Uri-typed JValues and then comparing against string constants in LINQ-to-JSON code; mixing Uri and string representations of the same URL.

Related errors


AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07). Data as JSON: /api/errors/e0199dbfc0b6be6e. Report an issue: GitHub.