OrchardCMS/OrchardCore · error · InvalidCastException

Cannot convert to DateTimeOffset

Error message

Cannot convert {value} to DateTimeOffset

What it means

JsonDynamicValue's explicit operator DateTimeOffset converts the wrapped JSON value via GetValue<DateTimeOffset>() and throws InvalidCastException when the result is null or the JSON token cannot be represented as a DateTimeOffset. The non-nullable operator deliberately fails fast; the nullable sibling returns null instead.

Solutions

  1. Ensure the JSON value is a parseable DateTimeOffset string (e.g. with offset like 2024-01-01T00:00:00+00:00)
  2. Use the nullable cast (DateTimeOffset?) and handle null instead of throwing
  3. Pre-parse with DateTimeOffset.TryParse/DateTimeOffset.Parse on value.ToString() when the format is uncertain
  4. Null-check the JsonDynamicValue wrapper before casting

Example fix

// before
var when = (DateTimeOffset)jsonDynamicValue["Timestamp"];
// after
var when = (DateTimeOffset?)jsonDynamicValue["Timestamp"] ?? DateTimeOffset.UtcNow;
Defensive patterns

Strategy: type-guard

Validate before calling

if (jsonDynamicValue is null) throw new InvalidOperationException("null wrapper");
var raw = jsonDynamicValue.ToString();
if (!DateTimeOffset.TryParse(raw, CultureInfo.InvariantCulture, DateTimeStyles.None, out _))
    throw new InvalidOperationException($"'{raw}' is not a DateTimeOffset");
var dto = (DateTimeOffset)jsonDynamicValue;

Type guard

static bool TryGetDateTimeOffset(JsonDynamicValue v, out DateTimeOffset value)
{
    value = default;
    if (v is null) return false;
    var dto = (DateTimeOffset?)v;
    if (dto is null) return false;
    value = dto.Value;
    return true;
}

Try / catch

DateTimeOffset dto;
try
{
    dto = (DateTimeOffset)jsonDynamicValue["Timestamp"];
}
catch (InvalidCastException ex)
{
    dto = DateTimeOffset.MinValue;
}

Prevention

When it happens

Trigger: Executing `(DateTimeOffset)jsonDynamicValue` where the wrapper or its _jsonValue is null, or the JSON token is a string lacking a timezone-offset-parseable value, a number, boolean, object, or array.

Common situations: Parsing timestamps from JSON payloads where the value is stored as a plain string without offset info or is null; deserializing API/document JSON with dynamic access; timezone-aware fields that were saved as empty strings.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/c0ef16fef33d240d. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs:318

    {
        return value?._jsonValue?.GetValue<char?>();
    }

    public static explicit operator DateTime(JsonDynamicValue value)
    {
        return value?._jsonValue?.GetValue<DateTime>()
            ?? throw new InvalidCastException($"Cannot convert {value} to DateTime");
    }

    public static explicit operator DateTime?(JsonDynamicValue value)
    {
        return value?._jsonValue?.GetValue<DateTime?>();
    }

    public static explicit operator DateTimeOffset(JsonDynamicValue value)
    {
        return value?._jsonValue?.GetValue<DateTimeOffset>()
            ?? throw new InvalidCastException($"Cannot convert {value} to DateTimeOffset");
    }

    public static explicit operator DateTimeOffset?(JsonDynamicValue value)
    {
        return value?._jsonValue?.GetValue<DateTimeOffset?>();
    }

    public static explicit operator decimal(JsonDynamicValue value)
    {
        return value?._jsonValue?.GetValue<decimal>()
            ?? throw new InvalidCastException($"Cannot convert {value} to Decimal");
    }

    public static explicit operator decimal?(JsonDynamicValue value)
    {
        return value?._jsonValue?.GetValue<decimal?>();
    }

View on GitHub (pinned to 4306c0717f)