elsa-workflows/elsa-core · error · TypeConversionException
Failed to deserialize
Error message
Failed to deserialize {stringValue} to {underlyingTargetType} What it means
ObjectConverter.ConvertTo attempts to JsonSerializer.Deserialize a string that starts with '{' or '[' into the target type. If deserialization fails for any reason it wraps the exception in a TypeConversionException reporting that it failed to deserialize the string value to the underlying target type.
Solutions
- Validate that the string is well-formed JSON and its shape matches the target type before conversion
- Use System.Text.Json to test-parse in a diagnostic step: JsonSerializer.Deserialize<T>(json) and inspect the JsonException for the offending path
- Enable strict mode off (default) to get a default value instead of an exception, or fix the payload in strict mode
- Check serializerOptions (naming policy, converters) match the payload conventions
Example fix
// before
var item = ObjectConverter.ConvertTo<TaskList>(rawJson, typeof(TaskList));
// after
if (typeof(TaskList).IsAssignableFrom(typeof(TaskList)) && !IsValidJson<TaskList>(rawJson))
throw new FormatException("Payload shape does not match TaskList");
var item = ObjectConverter.ConvertTo<TaskList>(rawJson, typeof(TaskList)); Defensive patterns
Strategy: validation
Validate before calling
bool isValidJson<T>(string s) { try { JsonSerializer.Deserialize<T>(s); return true; } catch (JsonException) { return false; } } Type guard
bool looksLikeJson(string s) => !string.IsNullOrWhiteSpace(s) && (s.TrimStart().StartsWith('{') || s.TrimStart().StartsWith('[')); Try / catch
try { value = ObjectConverter.ConvertTo(targetType, json); }
catch (TypeConversionException ex) { logger.LogError(ex, "Deserialization failed for {Target}", targetType); value = null; } Prevention
- Validate JSON shape against the target schema before binding
- Keep serializer options (naming policies) consistent between producer and consumer
- Check the inner exception path info to find the mismatched property
When it happens
Trigger: Converting a string starting with '{' or '[' (via ConvertTo/ObjectConverter) into a target type whose JSON does not match — e.g. passing a JSON array into a target expecting an object, malformed JSON, or a property name/type mismatch under the configured serializer options.
Common situations: Workflow inputs supplied as JSON text into object-typed variables, malformed JSON from clipboard/designer, or changing case-sensitivity/serializer options so previously matching payloads no longer deserialize.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- Cannot deserialize to .
- Failed to deserialize
- The binding to activity type
- Expected number or string.
- Cannot convert to bool
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/2d7e58ef02377272.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs:170
{
var stringValue = (string)value;
if (underlyingTargetType == typeof(byte[]))
{
// Byte arrays are serialized to base64, so in this case, we convert the string back to the requested target type of byte[].
return Convert.FromBase64String(stringValue);
}
try
{
var firstChar = stringValue.TrimStart().FirstOrDefault();
if (firstChar is '{' or '[')
return JsonSerializer.Deserialize(stringValue, underlyingTargetType, serializerOptions);
}
catch (Exception e)
{
throw new TypeConversionException($"Failed to deserialize {stringValue} to {underlyingTargetType}", value, underlyingTargetType, e);
}
}
if (targetType == typeof(object))
return value;
if (underlyingTargetType.IsInstanceOfType(value))
return value;
if (underlyingSourceType == underlyingTargetType)
return value;
if (IsDateType(underlyingSourceType) && IsDateType(underlyingTargetType))
return ConvertAnyDateType(value, underlyingTargetType);
var internalSerializerOptions = InternalSerializerOptions;
if (typeof(IDictionary<string, object>).IsAssignableFrom(underlyingSourceType) && (underlyingTargetType.IsClass || underlyingTargetType.IsInterface))View on GitHub (pinned to fe9217bdfa)