reactiveui/refit · error · JsonException
Problem details JSON must be an object.
Error message
Problem details JSON must be an object.
What it means
DeserializeProblemDetails throws JsonException when the parsed problem-details content's root JSON value is not an object (e.g. it is an array, a bare string/number, true/false, or null). RFC 7807 problem details must be a JSON object, so any other root kind is rejected after parsing succeeds.
Source
Thrown at src/Refit/ValidationApiException.cs:144
return new(exception);
}
/// <summary>Deserializes RFC 7807 problem details without requiring public setters on extension data.</summary>
/// <param name="content">The JSON problem details content.</param>
/// <returns>The deserialized problem details.</returns>
/// <exception cref="JsonException"><paramref name="content"/> is not valid JSON, or its root value is not an object.</exception>
internal static ProblemDetails DeserializeProblemDetails(string content)
{
#if NET10_0_OR_GREATER
var rootElement = JsonElement.Parse(content);
#else
using var document = JsonDocument.Parse(content);
var rootElement = document.RootElement;
#endif
if (rootElement.ValueKind != JsonValueKind.Object)
{
throw new JsonException("Problem details JSON must be an object.");
}
var problemDetails = new ProblemDetails();
foreach (var property in rootElement.EnumerateObject())
{
ReadProblemDetailsProperty(problemDetails, property);
}
return problemDetails;
}
/// <summary>Reads a single problem-details property.</summary>
/// <param name="problemDetails">The problem details instance to populate.</param>
/// <param name="property">The JSON property to read.</param>
internal static void ReadProblemDetailsProperty(
ProblemDetails problemDetails,
JsonProperty property)
{View on GitHub (pinned to b455f65ecc)
Solutions
- Ensure the server returns a single RFC 7807 problem-details JSON object as the response body
- If the API legitimately returns arrays/scalars, deserialize with a custom handler instead of ValidationApiException
- Inspect the raw content and content type before attempting problem-details deserialization
- Wrap deserialization in a try/catch for JsonException and fall back to ApiException
Example fix
// before
var validation = ex.AsValidation(); // throws if body is e.g. [ { ... }, { ... } ]
// after
try
{
var validation = ex.AsValidation();
}
catch (JsonException)
{
// body is valid JSON but not a problem-details object; handle generically
logger.LogWarning("Non-object problem body: {Body}", ex.Content);
throw;
} Defensive patterns
Strategy: try-catch
Validate before calling
static bool IsJsonObjectPayload(string content)
{
using var doc = JsonDocument.Parse(content);
return doc.RootElement.ValueKind == JsonValueKind.Object;
}
if (!string.IsNullOrWhiteSpace(ex.Content) && IsJsonObjectPayload(ex.Content))
var validation = ex.AsValidation(); Type guard
static bool IsProblemDetailsObject(string content)
{
try
{
using var doc = JsonDocument.Parse(content);
return doc.RootElement.ValueKind == JsonValueKind.Object;
}
catch { return false; }
} Try / catch
try { var validation = ex.AsValidation(); }
catch (JsonException ex) when (ex.Message.Contains("must be an object"))
{
// body is valid JSON but not an object; handle generically as ApiException
logger.LogWarning("Non-object problem body: {Body}", ex2.Content);
} Prevention
- Verify the response body is a JSON object before problem-details deserialization
- Wrap AsValidation() in a try/catch for JsonException and fall back to ApiException
- Log raw content when deserialization fails to diagnose server-side shape changes
- Add contract tests against the server's actual error envelope shape
When it happens
Trigger: The response body parses as valid JSON but its top-level value is not an object: a JSON array, a scalar, or a JSON null. Reached via ValidationApiException deserialization when the server returned a structurally valid but non-object payload claiming to be problem+json.
Common situations: A server returning a JSON array of errors instead of a single problem-details object; a proxy returning a scalar status; a misconfigured error formatter; version skew where the API changed its error envelope shape.
Related errors
- Unexpected parameter type in a Multipart request. Parameter
- Content must be an 'application/problem+json' compliant json
- Unexpected parameter type in a Multipart request. Parameter
- The configured content serializer '{RefitSettings.ContentSer
- Cannot convert an empty value to {typeof(TEnum)}.
AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13).
Data as JSON: /api/errors/d33cd9cc2ea660fe.
Report an issue: GitHub.