babalae/better-genshin-impact · error · Exception

Failed to deserialize JSON.

Error message

Failed to deserialize JSON.

What it means

Thrown in BaseMapLayerByTemplateMatch.LoadLayers when JsonSerializer.Deserialize<List<BaseMapLayerByTemplateMatch>>(json) returns null. System.Text.Json returns null when the JSON payload is the literal 'null' token or an empty/malformed file deserializes to null for a reference type. An empty array '[]' deserializes to an empty list (not null), so this specifically indicates a null-bearing document.

Source

Thrown at BetterGenshinImpact/GameTask/Common/Map/Maps/Base/BaseMapLayerByTemplateMatch.cs:59

        var grayMapPath = Path.Combine(layerDir, grayMapFileName);
        FineGrayMap = Bv.ImRead(grayMapPath, ImreadModes.Grayscale)?? throw new Exception($"灰度分层地图 {LayerId} 读取失败");
        speedTimer.Record("粗匹配用灰度图");
        speedTimer.DebugPrint();
    }

    public static List<BaseMapLayerByTemplateMatch> LoadLayers(SceneBaseMapByTemplateMatch sceneBaseMap)
    {
        var layers = new List<BaseMapLayerByTemplateMatch>();
        var layerDir = Path.Combine(Global.Absolute(@"Assets\Map\"), sceneBaseMap.Type.ToString());
        if (!Directory.Exists(layerDir))
        {
            return layers;
        }
        var jsonFiles = Directory.GetFiles(layerDir, "*.json", SearchOption.AllDirectories);
        foreach (var jsonFile in jsonFiles)
        {
            var json = File.ReadAllText(jsonFile);
            var tempLayers = JsonSerializer.Deserialize<List<BaseMapLayerByTemplateMatch>>(json) ?? throw new Exception("Failed to deserialize JSON.");
            layers.AddRange(tempLayers);
        }
        foreach (var layer in layers)
        {
            layer.LoadLayer(layerDir);
        }
        return layers;
    }
    
    public (Point2f, double) RoughMatch(Mat[] maskedMiniMaps, Mat maskF)
    {
        var (pos, val) = CoarseColorMatcher.Match(maskedMiniMaps, maskF);
        return (MapToWorld(pos, RoughZoom, RoughSize), val);
    }

    public (Point2f, double) RoughMatch(Mat[] maskedMiniMaps, Mat maskF, Point2f preLoc, int[]? channels = null)
    {
        var roughPos = WorldToMap(preLoc, RoughZoom);

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Open each *.json under Assets\Map\<Type> and find the one that is 'null' or empty; replace it with a valid layer array.
  2. Restrict the JSON search to files matching the layer naming scheme instead of all *.json.
  3. Treat null as an empty list rather than fatal: use 'tempLayers ?? new()' or skip the file with a warning.

Example fix

// before
var tempLayers = JsonSerializer.Deserialize<List<BaseMapLayerByTemplateMatch>>(json) ?? throw new Exception("Failed to deserialize JSON.");

// after — tolerate a null document and report which file is bad
var tempLayers = JsonSerializer.Deserialize<List<BaseMapLayerByTemplateMatch>>(json);
if (tempLayers == null || tempLayers.Count == 0)
{
    Logger.LogWarning("地图层 JSON 文件内容为空,已跳过: {File}", jsonFile);
    continue;
}
layers.AddRange(tempLayers);
Defensive patterns

Strategy: validation

Validate before calling

var json = File.ReadAllText(jsonFile);
if (string.IsNullOrWhiteSpace(json) || json.Trim() == "null")
{
    Logger.LogWarning("跳过空的地图层 JSON: {File}", jsonFile);
    continue;
}

Try / catch

try { var tempLayers = JsonSerializer.Deserialize<List<BaseMapLayerByTemplateMatch>>(json); }
catch (JsonException ex) { Logger.LogError(ex, "JSON 反序列化失败: {File}", jsonFile); throw; }

Prevention

When it happens

Trigger: LoadLayers reads every *.json under layerDir (recursive) and deserializes each. If any JSON file contains just 'null' (e.g. a placeholder, a mis-saved file, or an editor that wrote null), the result is null and this throws.

Common situations: A hand-edited or auto-generated JSON file contains the literal null; a file was truncated to empty and a default/null was written; an unrelated .json (e.g. a config) was placed in the map directory and happens to deserialize to null.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/dd09ac119849a557. Report an issue: GitHub.