Devolutions/UniGetUI · error · InvalidOperationException

The request body is required.

Error message

The request body is required.

What it means

Thrown by ReadJsonBodyAsync<TRequest> when IpcJson.Deserialize returns null after reading the request body. This happens when the body is empty/whitespace (the deserializer yields null) rather than a JSON syntax error (which throws earlier). The handler returns HTTP 400.

Source

Thrown at src/UniGetUI.Interface.IpcApi/IpcServer.cs:1853

            {
                await context.Response.WriteAsJsonAsync(
                    await action(await ReadJsonBodyAsync<TRequest>(context)),
                    IpcJson.Options
                );
            }
            catch (InvalidOperationException ex)
            {
                context.Response.StatusCode = 400;
                await context.Response.WriteAsync(ex.Message);
            }
        }

        private static async Task<TRequest> ReadJsonBodyAsync<TRequest>(HttpContext context)
        {
            using var reader = new StreamReader(context.Request.Body, Encoding.UTF8);
            var request = IpcJson.Deserialize<TRequest>(await reader.ReadToEndAsync());
            return request
                ?? throw new InvalidOperationException("The request body is required.");
        }

        private static IpcPackageActionRequest BuildPackageActionRequest(HttpRequest request)
        {
            return new IpcPackageActionRequest
            {
                PackageId = GetRequiredQueryValue(request, "packageId"),
                ManagerName = GetOptionalQueryValue(request, "manager"),
                PackageSource = GetOptionalQueryValue(request, "packageSource"),
                Version = GetOptionalQueryValue(request, "version"),
                Scope = GetOptionalQueryValue(request, "scope"),
                PreRelease = bool.TryParse(request.Query["preRelease"], out bool preRelease)
                    ? preRelease
                    : null,
                Elevated = bool.TryParse(request.Query["elevated"], out bool elevated)
                    ? elevated
                    : null,
                Interactive = bool.TryParse(request.Query["interactive"], out bool interactive)

View on GitHub (pinned to 9b1d7d0eab)

Solutions

  1. Send a valid JSON object for the request type, e.g. '{}' for an empty request DTO, with Content-Type: application/json.
  2. On the client, assert a non-empty body before issuing the request.
  3. If the endpoint legitimately accepts no fields, send the empty-object literal '{}' rather than nothing.

Example fix

// before: POST with empty body -> HTTP 400 "The request body is required."
// after:
var content = new StringContent("{}", Encoding.UTF8, "application/json");
var resp = await httpClient.PostAsync($"/v3/...?token={token}", content);
Defensive patterns

Strategy: validation

Validate before calling

// Client: ensure a non-empty JSON body before POSTing.
if (string.IsNullOrWhiteSpace(bodyJson))
    bodyJson = "{}";
var content = new StringContent(bodyJson, Encoding.UTF8, "application/json");
if (content.Headers.ContentLength == 0) throw new InvalidOperationException("body required");

Prevention

When it happens

Trigger: POSTing to a maintenance/action endpoint (HandleManagerMaintenanceActionAsync) with an empty Content-Length, a whitespace-only body, or a body that deserializes to a null reference for the request type.

Common situations: Client forgot to attach a JSON body; set Content-Type but sent an empty string; used a GET where the route expects a POST with a body; proxy stripped the body.

Related errors


AI-assisted analysis of Devolutions/UniGetUI@9b1d7d0eab (2026-08-13). Data as JSON: /api/errors/b938e1b51f6deadf. Report an issue: GitHub.