{"record":{"id":"538071c645f4a8de","repo":"JustArchiNET/ArchiSteamFarm","slug":"required-property-property-name-expects-a-non-nu","errorCode":null,"errorMessage":"Required property {property.Name} expects a non-null value.","messagePattern":"Required property (.+?) expects a non-null value\\.","errorType":"validation","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"ArchiSteamFarm/Helpers/Json/JsonUtilities.cs","lineNumber":188,"sourceCode":"\n\t\tresult = parent.GetMethod($\"ShouldSerialize{memberName}\", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, Type.EmptyTypes, null);\n\n\t\t// Use alternative method if it exists and returns a boolean\n\t\treturn result?.ReturnType == typeof(bool) ? result : null;\n\t}\n\n\t[UnconditionalSuppressMessage(\"AssemblyLoadTrimming\", \"IL2075\", Justification = \"We don't care about trimmed properties, it's not like we can make it work differently anyway\")]\n\tprivate static void OnPotentialDisallowedNullsDeserialized(object obj) {\n\t\tArgumentNullException.ThrowIfNull(obj);\n\n\t\tType type = obj.GetType();\n\n\t\tforeach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(field => field.IsDefined(typeof(JsonDisallowNullAttribute), false) && (field.GetValue(obj) == null))) {\n\t\t\tthrow new JsonException($\"Required field {field.Name} expects a non-null value.\");\n\t\t}\n\n\t\tforeach (PropertyInfo property in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(property => (property.GetMethod != null) && property.IsDefined(typeof(JsonDisallowNullAttribute), false) && (property.GetValue(obj) == null))) {\n\t\t\tthrow new JsonException($\"Required property {property.Name} expects a non-null value.\");\n\t\t}\n\t}\n\n\tprivate static bool ShouldSerialize(MethodInfo shouldSerializeMethod, object parent) {\n\t\tArgumentNullException.ThrowIfNull(shouldSerializeMethod);\n\t\tArgumentNullException.ThrowIfNull(parent);\n\n\t\tif (shouldSerializeMethod.ReturnType != typeof(bool)) {\n\t\t\tthrow new InvalidOperationException(nameof(shouldSerializeMethod));\n\t\t}\n\n\t\tobject? shouldSerialize = shouldSerializeMethod.Invoke(parent, null);\n\n\t\tif (shouldSerialize is not bool result) {\n\t\t\t// Should not happen, we've already determined we have a method that returns a boolean\n\t\t\tthrow new InvalidOperationException(nameof(shouldSerialize));\n\t\t}\n","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/JustArchiNET/ArchiSteamFarm/blob/fe57c4129f4ce02d452318cabc525eb49a087255/ArchiSteamFarm/Helpers/Json/JsonUtilities.cs#L170-L206","documentation":"Same OnPotentialDisallowedNullsDeserialized callback as error 0, but iterates properties instead of fields (requires a getter). Any property marked [JsonDisallowNullAttribute] whose GetValue(obj) returns null after deserialization raises this JsonException. This is the property counterpart to error 0 and fires for the same lifecycle reason.","triggerScenarios":"A config type's property annotated with JsonDisallowNullAttribute ends up null after deserialization because the JSON omitted the key, sent explicit null, the value failed type conversion, or the property had no setter so the deserializer could not populate it.","commonSituations":"Hand-editing a config and dropping a required property; version drift where a new required property was added; private/setter-less property that System.Text.Json cannot write; mismatched PropertyNamingPolicy leaving the property unbound.","solutions":["Locate the named property in the error and ensure the JSON supplies a non-null value with the correct name/casing.","Confirm the ASF build matches the config schema version.","Regenerate the config file from defaults to guarantee all required properties are present.","If authoring a type, ensure the annotated property has an accessible setter so it can be populated."],"exampleFix":"// before\n{ \"Enabled\": true }\n// after — supply the named required property\n{ \"Enabled\": true, \"PasswordFormat\": \"PlainText\" }","handlingStrategy":"validation","validationCode":"// Ensure every annotated required property is present before deserializing.\nvar required = typeof(BotConfig).GetProperties()\n    .Where(p => p.IsDefined(typeof(JsonDisallowNullAttribute), false))\n    .Select(p => p.Name);\nforeach (var name in required) {\n    if (!doc.RootElement.TryGetProperty(name, out var v) || v.ValueKind == JsonValueKind.Null)\n        throw new InvalidOperationException($\"Missing required property {name}\");\n}","typeGuard":null,"tryCatchPattern":"try { var cfg = JsonSerializer.Deserialize<T>(json, options); }\ncatch (JsonException ex) when (ex.Message.Contains(\"expects a non-null value\")) {\n    logger.LogError(ex, \"Required config property missing/null\");\n}","preventionTips":["When authoring config types, keep required properties with setters and document them.","Validate config JSON against the expected schema before deployment.","Regenerate configs from ASF defaults after major version upgrades."],"tags":["json","deserialization","configuration","validation","system-text-json"],"backgroundTag":null,"analyzedSha":"fe57c4129f4ce02d452318cabc525eb49a087255","analyzedAt":"2026-08-13T17:26:20.146Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}