JamesNK/Newtonsoft.Json · error · ArgumentOutOfRangeException

Unexpected token when writing BSON: {0}

Error message

Unexpected token when writing BSON: {0}

What it means

Thrown by BsonBinaryWriter.WriteValue's default case when it encounters a BsonToken whose Type is not one of the handled BsonType values (Object, Array, Integer, Long, Number, String, Boolean, Null, Undefined, Date, Binary, Oid, Regex). It is an ArgumentOutOfRangeException indicating the BSON writer received a token it does not know how to serialize to binary. Because BsonWriter constructs these tokens internally from public Write* calls, this normally signals an internal/unsupported value path rather than a typical user mistake.

Source

Thrown at Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs:191

                    break;
                case BsonType.Oid:
                {
                    BsonValue value = (BsonValue)t;

                    byte[] data = (byte[])value.Value;
                    _writer.Write(data);
                }
                    break;
                case BsonType.Regex:
                {
                    BsonRegex value = (BsonRegex)t;

                    WriteString((string)value.Pattern.Value, value.Pattern.ByteCount, null);
                    WriteString((string)value.Options.Value, value.Options.ByteCount, null);
                }
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(t), "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
            }
        }

        private void WriteString(string s, int byteCount, int? calculatedlengthPrefix)
        {
            if (calculatedlengthPrefix != null)
            {
                _writer.Write(calculatedlengthPrefix.GetValueOrDefault());
            }

            WriteUtf8Bytes(s, byteCount);

            _writer.Write((byte)0);
        }

        public void WriteUtf8Bytes(string s, int byteCount)
        {
            if (s != null)

View on GitHub (pinned to 4f73e74372)

Solutions

  1. Inspect the exception message: the {0} placeholder is filled with the offending BsonType; remove or convert the value producing that token type.
  2. Add a custom JsonConverter/BsonConverter for the CLR type that triggered the unsupported token so it serializes as a supported BSON primitive (string, bytes, integer).
  3. If you are manually constructing BsonToken trees, ensure every leaf uses only supported BsonType values.
  4. Migrate from the obsolete in-box BSON classes to the dedicated Newtonsoft.Json.Bson NuGet package.

Example fix

// before: Guid property serializes to an unsupported token
new BsonWriter(stream);
serializer.Serialize(bsonWriter, modelWithGuid);

// after: convert Guid to a 16-byte binary value before BSON serialization
var settings = new JsonSerializerSettings();
settings.Converters.Add(new GuidToBinaryConverter()); // writes Guid as BsonType.Binary
Defensive patterns

Strategy: validation

Validate before calling

// Before serializing, ensure every leaf value maps to a supported BSON primitive.
static bool IsBsonSupported(object value) =>
    value == null
    || value is int || value is long || value is double || value is decimal
    || value is bool || value is string || value is byte[]
    || value is DateTime || value is DateTimeOffset
    || value is Newtonsoft.Json.Bson.BsonObjectId;

if (!graph.All(IsBsonSupported)) throw new InvalidOperationException("unsupported BSON type");

Type guard

static bool IsSupportedBsonType(Newtonsoft.Json.Bson.BsonType t) =>
    t == Newtonsoft.Json.Bson.BsonType.Object
    || t == Newtonsoft.Json.Bson.BsonType.Array
    || t == Newtonsoft.Json.Bson.BsonType.Integer
    || t == Newtonsoft.Json.Bson.BsonType.Long
    || t == Newtonsoft.Json.Bson.BsonType.Number
    || t == Newtonsoft.Json.Bson.BsonType.String
    || t == Newtonsoft.Json.Bson.BsonType.Boolean
    || t == Newtonsoft.Json.Bson.BsonType.Null
    || t == Newtonsoft.Json.Bson.BsonType.Undefined
    || t == Newtonsoft.Json.Bson.BsonType.Date
    || t == Newtonsoft.Json.Bson.BsonType.Binary
    || t == Newtonsoft.Json.Bson.BsonType.Oid
    || t == Newtonsoft.Json.Bson.BsonType.Regex;

Try / catch

try { serializer.Serialize(bsonWriter, obj); }
catch (ArgumentOutOfRangeException ex) when (ex.Message.Contains("Unexpected token when writing BSON"))
{
    // log the offending BsonType, convert the offending value, or fall back to JSON
    throw new InvalidOperationException("Unsupported BSON token type", ex);
}

Prevention

When it happens

Trigger: Calling BsonWriter methods that produce an unsupported combination, e.g. writing a value whose runtime type cannot be mapped to a known BsonType, or directly feeding a hand-constructed BsonToken tree (BsonWriter.WriteValue with a BsonObject/BsonArray tree containing an exotic token) into the writer. Also reachable when serializing an object graph that yields a token type the BSON writer never expected (e.g. a Guid that is not wrapped as Oid/Binary).

Common situations: Using the obsolete Newtonsoft BSON support on a data model with types BSON does not natively represent (e.g. Guid without a converter, complex nested values). Migrating from the in-box BSON to the separate Newtonsoft.Json.Bson package and hitting a behavior gap. Manually building BsonToken trees in tests.

Understand the failure class

Related errors


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