{"record":{"id":"97ce96d030289d3b","repo":"elsa-workflows/elsa-core","slug":"the-upstream-logout-mode-must-be-a-string","errorCode":null,"errorMessage":"The upstream logout mode must be a string.","messagePattern":"The upstream logout mode must be a string\\.","errorType":"validation","errorClass":"JsonException","httpStatus":400,"severity":"error","filePath":"src/modules/Elsa.ExternalAuthentication/Endpoints/Connections/ConnectionManagementModels.cs","lineNumber":191,"sourceCode":"                ? null\n                : new ConnectionObservationResponse(\n                    observation.Status.ToString().ToLowerInvariant(),\n                    observation.ObservedAt,\n                    observation.TestedMaterialRevision,\n                    !string.Equals(observation.TestedMaterialRevision, effective.Connection.MaterialRevision, StringComparison.Ordinal),\n                    observation.Category,\n                    observation.Summary)\n        };\n    }\n\n}\n\ninternal sealed class UpstreamLogoutModeJsonConverter : JsonConverter<UpstreamLogoutMode>\n{\n    public override UpstreamLogoutMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (reader.TokenType != JsonTokenType.String)\n            throw new JsonException(\"The upstream logout mode must be a string.\");\n\n        return reader.GetString()?.ToLowerInvariant() switch\n        {\n            \"disabled\" => UpstreamLogoutMode.Disabled,\n            \"userchoice\" or \"user-choice\" or \"user_choice\" => UpstreamLogoutMode.UserChoice,\n            \"always\" => UpstreamLogoutMode.Always,\n            _ => throw new JsonException(\"The upstream logout mode is not supported.\")\n        };\n    }\n\n    public override void Write(Utf8JsonWriter writer, UpstreamLogoutMode value, JsonSerializerOptions options) =>\n        writer.WriteStringValue(value switch\n        {\n            UpstreamLogoutMode.Disabled => \"disabled\",\n            UpstreamLogoutMode.UserChoice => \"user-choice\",\n            UpstreamLogoutMode.Always => \"always\",\n            _ => throw new JsonException(\"The upstream logout mode is not supported.\")\n        });","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.ExternalAuthentication/Endpoints/Connections/ConnectionManagementModels.cs#L173-L209","documentation":"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.","triggerScenarios":"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\".","commonSituations":"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.","solutions":["Send the value as a JSON string: \"disabled\", \"user-choice\", or \"always\".","Check the client serializer is not writing enum numeric values for this field (use string enum handling).","Wrap deserialization in try/catch for JsonException and return a 400 validation error naming the field."],"exampleFix":"// before\n{\"upstreamLogoutMode\": 2}\n// after\n{\"upstreamLogoutMode\": \"user-choice\"}","handlingStrategy":"validation","validationCode":"if (payload.UpstreamLogoutMode is not string s || s is null)\n    throw new ArgumentException(\"upstreamLogoutMode must be a JSON string\");","typeGuard":"bool IsValidLogoutModeToken(JsonTokenType t) => t == JsonTokenType.String;","tryCatchPattern":"try { mode = JsonSerializer.Deserialize<ConnectionModel>(json); }\ncatch (JsonException ex) when (ex.Message.Contains(\"upstream logout mode\"))\n{ /* return 400 with field error */ }","preventionTips":["Always serialize enums as strings in clients","Validate request payloads with schema validation before deserialization","Add API tests that post each accepted mode value"],"tags":["json","serialization","enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}