{"record":{"id":"ec1bc1c2bcd68f0a","repo":"OrchardCMS/OrchardCore","slug":"unable-to-convert-stringvalue-to-timespan","errorCode":null,"errorMessage":"Unable to convert '{stringValue}' to TimeSpan.","messagePattern":"Unable to convert '(.+?)' to TimeSpan\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore.Abstractions/Json/Serialization/TimeSpanJsonConverter.cs","lineNumber":24,"sourceCode":"public class TimeSpanJsonConverter : JsonConverter<TimeSpan>\n{\n    public static readonly TimeSpanJsonConverter Instance = new();\n\n    public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (reader.TokenType != JsonTokenType.String)\n        {\n            throw new JsonException($\"Unexpected token parsing TimeSpan. Expected a string, got '{reader.TokenType}'.\");\n        }\n\n        var stringValue = reader.GetString();\n\n        if (TimeSpan.TryParse(stringValue, out var timeSpan))\n        {\n            return timeSpan;\n        }\n\n        throw new JsonException($\"Unable to convert '{stringValue}' to TimeSpan.\");\n    }\n\n    public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)\n        => writer.WriteStringValue(value.ToString());\n}\n","sourceCodeStart":6,"sourceCodeEnd":30,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore.Abstractions/Json/Serialization/TimeSpanJsonConverter.cs#L6-L30","documentation":"TimeSpanJsonConverter.Read parses a JSON string into a TimeSpan using TimeSpan.TryParse. If the string is not in a recognizable time-span format (invariant culture), the converter throws JsonException, which surfaces during JsonSerializer.Deserialize as a JsonException wrapping the message.","triggerScenarios":"Deserializing a JSON property typed TimeSpan whose value string cannot be parsed, e.g. '\"duration\": \"1 hour\"', '\"duration\": \"\"', or a culture-specific format like '1,2:30' not valid invariantly. Also thrown when a non-string JSON token (number/null) is read because the reader tries GetString conversion paths.","commonSituations":"Reading persisted settings or content-item JSON written by another system or locale, hand-edited appsettings values like '90 minutes', API payloads from non-.NET clients using ISO-8601 durations ('PT1H') which TimeSpan.TryParse does not accept, or upgrading serialized data where the format changed.","solutions":["Store the value in a format TimeSpan.Parse accepts invariantly (e.g. '1.02:03:04', '01:30:00') and re-serialize the offending document.","Pre-parse the JSON manually: read the property as string, normalize it (convert ISO-8601 durations via XmlConvert.ToTimeSpan), then deserialize.","Catch JsonException around Deserialize and handle invalid duration values with a default.","If round-tripping across cultures, use XmlConvert.ToString/ToTimeSpan on a string property instead of relying on the converter."],"exampleFix":"// before\nvar options = new TimeSpan(\"1 hour\"); // JSON: \"1 hour\"\n// after\n// JSON: \"1.00:00:00\" or normalize before deserializing\nvar raw = (string?)json[\"duration\"];\nvar ts = TimeSpan.TryParse(raw, CultureInfo.InvariantCulture, out var v) ? v : TimeSpan.Zero;","handlingStrategy":"validation","validationCode":"if (!TimeSpan.TryParse(raw, CultureInfo.InvariantCulture, out var ts)) throw new FormatException($\"Invalid TimeSpan value: {raw}\");","typeGuard":"static bool IsValidTimeSpan(string? s) => TimeSpan.TryParse(s, CultureInfo.InvariantCulture, out _);","tryCatchPattern":"try { var v = JsonSerializer.Deserialize<MyDto>(json); }\ncatch (JsonException ex) when (ex.Message.Contains(\"to TimeSpan\")) { /* use default / report invalid duration */ }","preventionTips":["Always serialize TimeSpan with invariant culture formats","Never accept ISO-8601 durations (PT1H) directly into TimeSpan-typed JSON properties","Validate duration strings before persisting them to JSON documents"],"tags":["json","serialization","timespan","deserialization"],"backgroundTag":"invalid-duration-format","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}