elsa-workflows/elsa-core · error · JsonException

The upstream logout mode must be a string.

Error message

The upstream logout mode must be a string.

What it means

Thrown by UpstreamLogoutModeJsonConverter.Read when the incoming JSON token for an UpstreamLogoutMode property is not a JSON string (e.g. a number, object, or null literal). The converter only maps string tokens to enum values, so any other token type is rejected with a JsonException before the value switch runs.

Solutions

  1. Send the value as a JSON string: "disabled", "user-choice", or "always".
  2. Check the client serializer is not writing enum numeric values for this field (use string enum handling).
  3. Wrap deserialization in try/catch for JsonException and return a 400 validation error naming the field.

Example fix

// before
{"upstreamLogoutMode": 2}
// after
{"upstreamLogoutMode": "user-choice"}
Defensive patterns

Strategy: validation

Validate before calling

if (payload.UpstreamLogoutMode is not string s || s is null)
    throw new ArgumentException("upstreamLogoutMode must be a JSON string");

Type guard

bool IsValidLogoutModeToken(JsonTokenType t) => t == JsonTokenType.String;

Try / catch

try { mode = JsonSerializer.Deserialize<ConnectionModel>(json); }
catch (JsonException ex) when (ex.Message.Contains("upstream logout mode"))
{ /* return 400 with field error */ }

Prevention

When it happens

Trigger: Deserializing an identity-provider connection payload where the upstream logout mode field is sent as a number, boolean, object, array, or JSON null instead of a quoted string such as "disabled".

Common situations: Hand-written JSON in API clients or Postman collections omitting quotes; strongly-typed clients sending the raw enum integer; upstream IdP config exports that encode the mode as a numeric constant.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/97ce96d030289d3b. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.ExternalAuthentication/Endpoints/Connections/ConnectionManagementModels.cs:191

                ? null
                : new ConnectionObservationResponse(
                    observation.Status.ToString().ToLowerInvariant(),
                    observation.ObservedAt,
                    observation.TestedMaterialRevision,
                    !string.Equals(observation.TestedMaterialRevision, effective.Connection.MaterialRevision, StringComparison.Ordinal),
                    observation.Category,
                    observation.Summary)
        };
    }

}

internal sealed class UpstreamLogoutModeJsonConverter : JsonConverter<UpstreamLogoutMode>
{
    public override UpstreamLogoutMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.String)
            throw new JsonException("The upstream logout mode must be a string.");

        return reader.GetString()?.ToLowerInvariant() switch
        {
            "disabled" => UpstreamLogoutMode.Disabled,
            "userchoice" or "user-choice" or "user_choice" => UpstreamLogoutMode.UserChoice,
            "always" => UpstreamLogoutMode.Always,
            _ => throw new JsonException("The upstream logout mode is not supported.")
        };
    }

    public override void Write(Utf8JsonWriter writer, UpstreamLogoutMode value, JsonSerializerOptions options) =>
        writer.WriteStringValue(value switch
        {
            UpstreamLogoutMode.Disabled => "disabled",
            UpstreamLogoutMode.UserChoice => "user-choice",
            UpstreamLogoutMode.Always => "always",
            _ => throw new JsonException("The upstream logout mode is not supported.")
        });

View on GitHub (pinned to fe9217bdfa)