tursodatabase/turso · error · ArgumentException

Cannot convert {sourceType} to {targetType}.

Error message

Cannot convert {sourceType} to {targetType}.

What it means

ArgumentException thrown by ConvertEnum when the value being stored is a boxed enum of a different enum type than the target option — for example assigning a DateTimeKind to the 'Mode' keyword or a SqliteCacheMode to 'DateTimeKind'. The binding refuses cross-enum conversion because the underlying numeric meanings differ. Strings and non-enum values follow other paths, so this fires specifically for mismatched enum-typed objects.

Source

Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteConnectionStringBuilder.cs:347

            "DateTimeKind" => System.DateTimeKind.Unspecified,
            "DateTimeFormat" => string.Empty,
            "BinaryGUID" => true,
            "Version" => 3,
            _ => throw new ArgumentException(Properties.Resources.KeywordNotSupported(keyword)),
        };
    }

    private static TEnum ConvertEnum<TEnum>(object value)
        where TEnum : struct
    {
        if (value is TEnum typedValue)
            return typedValue;

        if (value is string stringValue)
            return Enum.Parse<TEnum>(stringValue, ignoreCase: true);

        if (value.GetType().IsEnum && value is not TEnum)
            throw new ArgumentException(Properties.Resources.ConvertFailed(value.GetType(), typeof(TEnum)));

        var enumValue = (TEnum)Enum.ToObject(typeof(TEnum), value);
        if (!Enum.IsDefined(typeof(TEnum), enumValue))
            throw new ArgumentOutOfRangeException(nameof(value), value, Properties.Resources.InvalidEnumValue(typeof(TEnum), enumValue));

        return enumValue;
    }

    private static bool? ConvertToNullableBoolean(object value)
        => value is null or string { Length: 0 }
            ? null
            : Convert.ToBoolean(value, CultureInfo.InvariantCulture);

    private static SqliteOpenMode ConvertOpenMode(object value)
    {
        var mode = ConvertEnum<SqliteOpenMode>(value);
        if (!Enum.IsDefined(mode))
            throw new ArgumentOutOfRangeException(nameof(value), value, Properties.Resources.InvalidEnumValue(typeof(SqliteOpenMode), mode));

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Assign the correct enum type to each keyword: SqliteOpenMode for Mode, SqliteCacheMode for Cache, DateTimeKind for DateTimeKind.
  2. Prefer the typed properties (builder.Mode = ..., builder.DateTimeKind = ...) which make the mistake a compile error.
  3. In generic loaders, convert to the expected type via Enum.Parse(targetType, value.ToString()) or store the string form, which the binder parses by name.

Example fix

// before
builder["DateTimeKind"] = SqliteCacheMode.Shared; // wrong enum type

// after
builder["DateTimeKind"] = DateTimeKind.Utc;
Defensive patterns

Strategy: type-guard

Validate before calling

static object ConvertForKeyword(string keyword, object value) => keyword switch
{
    "Mode" when value is string or SqliteOpenMode => value,
    "Cache" when value is string or SqliteCacheMode => value,
    "DateTimeKind" when value is string or DateTimeKind => value,
    _ => throw new ConfigException($"Value type {value?.GetType().Name} wrong for {keyword}"),
};

Type guard

static bool MatchesKeywordType(string keyword, object value) => keyword switch
{
    "Mode" => value is string or SqliteOpenMode,
    "Cache" => value is string or SqliteCacheMode,
    "DateTimeKind" => value is string or DateTimeKind,
    _ => value is string,
};

Try / catch

try { builder[kw] = value; }
catch (ArgumentException ex) when (ex.Message.Contains("Cannot convert"))
{ /* convert value to string first: builder[kw] = value.ToString() */ }

Prevention

When it happens

Trigger: builder["Mode"] = DateTimeKind.Utc; builder["DateTimeKind"] = SqliteCacheMode.Shared; passing a boxed foreign enum from generic/config code like builder[keyword] = Enum.Parse(otherEnumType, text).

Common situations: Generic configuration loaders that store parsed enum objects by keyword name; copy-paste between option lines swapping the values; dictionary-driven setups mapping config sections to keywords by reflection.

Related errors


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