{"record":{"id":"aaaba46c17314885","repo":"elsa-workflows/elsa-core","slug":"expected-a-string-metadata-value","errorCode":null,"errorMessage":"Expected a string metadata value.","messagePattern":"Expected a string metadata value\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Secrets/Models/OrdinalIgnoreCaseDictionaryConverter.cs","lineNumber":33,"sourceCode":"\n        var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);\n        while (reader.Read())\n        {\n            if (reader.TokenType == JsonTokenType.EndObject)\n                return values;\n\n            if (reader.TokenType != JsonTokenType.PropertyName)\n                throw new JsonException(\"Expected a metadata property name.\");\n\n            var key = reader.GetString()!;\n            if (!reader.Read())\n                throw new JsonException(\"Unexpected end of JSON while reading secret metadata.\");\n\n            if (reader.TokenType == JsonTokenType.Null)\n                continue;\n\n            if (reader.TokenType != JsonTokenType.String)\n                throw new JsonException(\"Expected a string metadata value.\");\n\n            var value = reader.GetString();\n            if (value != null)\n                values[key] = value;\n        }\n\n        throw new JsonException(\"Unexpected end of JSON while reading secret metadata.\");\n    }\n\n    public override void Write(Utf8JsonWriter writer, IDictionary<string, string> value, JsonSerializerOptions options)\n    {\n        writer.WriteStartObject();\n        foreach (var item in value.OrderBy(x => x.Key, StringComparer.OrdinalIgnoreCase))\n            writer.WriteString(item.Key, item.Value);\n        writer.WriteEndObject();\n    }\n}\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Secrets/Models/OrdinalIgnoreCaseDictionaryConverter.cs#L15-L51","documentation":"This JsonException is thrown by OrdinalIgnoreCaseDictionaryConverter.Read when deserializing a secret metadata dictionary and a property's value token is not a JSON string (and not null). The converter only accepts string values (or null, which is skipped), so any number, boolean, array, or nested object in the metadata object is rejected.","triggerScenarios":"Calling JsonSerializer.Deserialize on a payload containing a secret metadata dictionary (e.g. Secret.Metadata) where one of the properties is a non-string JSON value such as {\"ttl\": 30} or {\"enabled\": true} instead of {\"ttl\": \"30\"}.","commonSituations":"Hand-edited or migrated secret JSON files, API clients that send numeric/boolean metadata, or older data formats where metadata values were loosely typed before the converter enforced string-only values.","solutions":["Convert all metadata values to JSON strings in the source payload (e.g. 30 -> \"30\", true -> \"true\").","Fix the producer/client so metadata values are serialized as strings before persisting or sending them.","If non-string values are required, change the property type to Dictionary<string, string> with a permissive converter or Dictionary<string, JsonElement> instead of using this converter.","If migrating old data, run a one-time migration that stringifies metadata values."],"exampleFix":"// before\nvar secret = JsonSerializer.Deserialize<Secret>(json); // metadata: {\"ttl\": 30}\n// after\n// fix the JSON: {\"ttl\": \"30\"}\nvar secret = JsonSerializer.Deserialize<Secret>(json);","handlingStrategy":"validation","validationCode":"// Validate all metadata values are strings before serializing/deserializing\nbool MetadataIsStringOnly(IDictionary<string, string> metadata) =>\n    metadata.Values.All(v => v is string);","typeGuard":"bool IsStringMetadata(JsonElement prop) => prop.ValueKind == JsonValueKind.String;","tryCatchPattern":"try { var secret = JsonSerializer.Deserialize<Secret>(json); }\ncatch (JsonException e) when (e.Message.Contains(\"Expected a string metadata value\")) { /* repair metadata JSON or reject payload */ }","preventionTips":["Always model metadata as Dictionary<string, string> and stringify numbers/booleans at the source.","Add JSON schema validation for secret payloads before persisting them.","Cover metadata serialization round-trips with unit tests."],"tags":["json","deserialization","secrets","type-mismatch"],"backgroundTag":"type-mismatch","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"}