tursodatabase/turso · error · JsonException

Extensions must be "all" or an array of extension names.

Error message

Extensions must be "all" or an array of extension names.

What it means

The Extensions union deserializes from exactly two shapes: the string "all" or an array of extension names. Any other JSON token for the "extensions" property — boolean, number, object, or a string other than "all" (e.g. "crypto", "crypto,regexp") — throws JsonException with this message during deserialization.

Source

Thrown at bindings/dotnet/src/Turso.Platform.Client/TursoPlatformClient.Supplement.cs:39

        ArgumentNullException.ThrowIfNull(names);
        return new Extensions(names.ToArray());
    }

    /// <summary>The explicitly enabled extension names, or <see langword="null"/> for <see cref="All"/>.</summary>
    public IReadOnlyList<string>? Names { get; }
}

internal sealed class ExtensionsJsonConverter : System.Text.Json.Serialization.JsonConverter<Extensions>
{
    public override Extensions Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
    {
        return reader.TokenType switch
        {
            System.Text.Json.JsonTokenType.String when reader.GetString() == "all" => Extensions.All,
            System.Text.Json.JsonTokenType.StartArray => Extensions.FromNames(
                System.Text.Json.JsonSerializer.Deserialize<string[]>(ref reader, options)
                ?? throw new System.Text.Json.JsonException("Extensions array cannot be null.")),
            _ => throw new System.Text.Json.JsonException("Extensions must be \"all\" or an array of extension names."),
        };
    }

    public override void Write(System.Text.Json.Utf8JsonWriter writer, Extensions value, System.Text.Json.JsonSerializerOptions options)
    {
        if (value.Names is null)
        {
            writer.WriteStringValue("all");
            return;
        }

        System.Text.Json.JsonSerializer.Serialize(writer, value.Names, options);
    }
}

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Fix the payload: "extensions": "all" or "extensions": ["crypto", "regexp"].
  2. Use the Extensions class (Extensions.All, Extensions.FromNames(...)) and let its converter serialize correctly.
  3. If you expose your own config surface, map booleans to the union (true -> "all", false -> omit) before sending.
  4. Validate outgoing bodies against the Platform API schema in CI to catch shape regressions.

Example fix

// before
{ "extensions": true }

// after
{ "extensions": "all" }
// or
{ "extensions": ["crypto", "regexp"] }
Defensive patterns

Strategy: validation

Validate before calling

// accept only the two legal shapes before sending
static bool IsValidExtensions(JsonElement e) =>
    (e.ValueKind == JsonValueKind.String && e.GetString() == "all")
    || (e.ValueKind == JsonValueKind.Array && e.EnumerateArray().All(x => x.ValueKind == JsonValueKind.String));

Type guard

static bool IsExtensionsPayload(object o) => o is Extensions;

Try / catch

try { await client.CreateGroupAsync(payload); }
catch (JsonException ex) when (ex.Message.Contains("extensions")) { /* normalize the field to \"all\" or a name array and retry */ }

Prevention

When it happens

Trigger: POSTing a group-create/update payload with "extensions": true, "extensions": "crypto", or "extensions": {"names":[...]}; any wrapper that flattens the union to a flag or comma-separated string instead of the two supported shapes.

Common situations: Hand-crafted REST calls or integrations built against older API shapes; wrappers exposing a bool enableExtensions that serializes directly; copy-pasting example payloads that predate the union type.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/112d68d108d0be18. Report an issue: GitHub.