JustArchiNET/ArchiSteamFarm · error · JsonException

Required property {property.Name} expects a non-null value.

Error message

Required property {property.Name} expects a non-null value.

What it means

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.

Source

Thrown at ArchiSteamFarm/Helpers/Json/JsonUtilities.cs:188

		result = parent.GetMethod($"ShouldSerialize{memberName}", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, Type.EmptyTypes, null);

		// Use alternative method if it exists and returns a boolean
		return result?.ReturnType == typeof(bool) ? result : null;
	}

	[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2075", Justification = "We don't care about trimmed properties, it's not like we can make it work differently anyway")]
	private static void OnPotentialDisallowedNullsDeserialized(object obj) {
		ArgumentNullException.ThrowIfNull(obj);

		Type type = obj.GetType();

		foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(field => field.IsDefined(typeof(JsonDisallowNullAttribute), false) && (field.GetValue(obj) == null))) {
			throw new JsonException($"Required field {field.Name} expects a non-null value.");
		}

		foreach (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))) {
			throw new JsonException($"Required property {property.Name} expects a non-null value.");
		}
	}

	private static bool ShouldSerialize(MethodInfo shouldSerializeMethod, object parent) {
		ArgumentNullException.ThrowIfNull(shouldSerializeMethod);
		ArgumentNullException.ThrowIfNull(parent);

		if (shouldSerializeMethod.ReturnType != typeof(bool)) {
			throw new InvalidOperationException(nameof(shouldSerializeMethod));
		}

		object? shouldSerialize = shouldSerializeMethod.Invoke(parent, null);

		if (shouldSerialize is not bool result) {
			// Should not happen, we've already determined we have a method that returns a boolean
			throw new InvalidOperationException(nameof(shouldSerialize));
		}

View on GitHub (pinned to fe57c4129f)

Solutions

  1. Locate the named property in the error and ensure the JSON supplies a non-null value with the correct name/casing.
  2. Confirm the ASF build matches the config schema version.
  3. Regenerate the config file from defaults to guarantee all required properties are present.
  4. If authoring a type, ensure the annotated property has an accessible setter so it can be populated.

Example fix

// before
{ "Enabled": true }
// after — supply the named required property
{ "Enabled": true, "PasswordFormat": "PlainText" }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every annotated required property is present before deserializing.
var required = typeof(BotConfig).GetProperties()
    .Where(p => p.IsDefined(typeof(JsonDisallowNullAttribute), false))
    .Select(p => p.Name);
foreach (var name in required) {
    if (!doc.RootElement.TryGetProperty(name, out var v) || v.ValueKind == JsonValueKind.Null)
        throw new InvalidOperationException($"Missing required property {name}");
}

Try / catch

try { var cfg = JsonSerializer.Deserialize<T>(json, options); }
catch (JsonException ex) when (ex.Message.Contains("expects a non-null value")) {
    logger.LogError(ex, "Required config property missing/null");
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of JustArchiNET/ArchiSteamFarm@fe57c4129f (2026-08-13). Data as JSON: /api/errors/538071c645f4a8de. Report an issue: GitHub.