d2phap/ImageGlass · critical · FileLoadException

IGE: Could not parse merged config.

Error message

IGE: Could not parse merged config.

What it means

Thrown by Config_Static when JsonSerializer.Deserialize returns null after merging the default, user, CLI-override, and admin JSON config layers into a single byte array. The deserializer returned null rather than throwing, meaning the merged JSON parsed to a JSON null (or the merged byte array was empty/null) instead of a valid Config object. Wrapped in a FileLoadException and stored on LoadingException.

Source

Thrown at source/ImageGlass.Lib/Settings/Config_Static.cs:589

            // 4. read igconfig.admin.json (BaseDir, then ConfigDir). Merge-only layer.
            using var adminDoc = ReadAdminConfigDocument();

            // 5. drop incompatible older layers; flag an incompatible user file so startup can warn
            var effectiveDefaultDoc = IsCompatibleConfigLayer(defaultDoc) ? defaultDoc : null;
            var effectiveAdminDoc = IsCompatibleConfigLayer(adminDoc) ? adminDoc : null;
            var effectiveUserDoc = userDoc;
            if (!IsCompatibleConfigLayer(userDoc))
            {
                effectiveUserDoc = null;
                IncompatibleUserConfigPath = userConfigPath;
            }

            // 6. merge the compatible layers into a single JSON byte array
            var mergedJson = MergeJsonLayers(effectiveDefaultDoc, effectiveUserDoc, cliOverrides, effectiveAdminDoc);

            // 7. deserialize the merged JSON into Config
            var config = JsonSerializer.Deserialize(mergedJson, jsonContext.Config)
                ?? throw new FileLoadException("IGE: Could not parse merged config.");

            // 8. migrate if config version changed
            appConfig = MigrateUserConfigFile(config);

            // 9. apply persisted tool configs derived from the merged config
            ApplyPersistedToolConfigs(appConfig);
        }
        catch (Exception ex)
        {
            LoadingException = ex;
        }

        appConfig ??= new();

        // seed pre-configured external tools; also runs on a failed load so they still work
        EnsurePredefinedTools(appConfig);

        return appConfig;

View on GitHub (pinned to 4a3c4fecef)

Solutions

  1. Inspect LoadingException.InnerException and the mergedJson bytes (log them at startup) to see if the merged document is `null`, empty, or a non-object.
  2. Restore or regenerate igconfig.json — delete it so the app re-creates it from defaults on next start.
  3. Ensure the default config layer (shipped with the app) is present and is a JSON object, not null.
  4. If caused by CLI overrides (--Config:* args), check that the override syntax produces a value, not a whole-object replacement with null.

Example fix

// before
var config = JsonSerializer.Deserialize(mergedJson, jsonContext.Config)
    ?? throw new FileLoadException("IGE: Could not parse merged config.");

// after — include a snippet of the merged JSON to make the null parse diagnosable
var config = JsonSerializer.Deserialize(mergedJson, jsonContext.Config);
if (config is null)
{
    var preview = mergedJson is null ? "<null>" : Encoding.UTF8.GetString(mergedJson);
    if (preview.Length > 200) preview = preview[..200] + "...";
    throw new FileLoadException($"IGE: Could not parse merged config (parsed to null). Merged JSON: {preview}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before deserialize, confirm the merged JSON is a non-null object document.
if (mergedJson is null || mergedJson.Length == 0) throw new FileLoadException("Merged config is empty");
using var doc = JsonDocument.Parse(mergedJson);
if (doc.RootElement.ValueKind != JsonValueKind.Object) throw new FileLoadException($"Merged config is {doc.RootElement.ValueKind}, expected object");

Type guard

static bool IsMergedObject(byte[] json)
{
    if (json is null || json.Length == 0) return false;
    using var d = JsonDocument.Parse(json);
    return d.RootElement.ValueKind == JsonValueKind.Object;
}

Try / catch

try { Config.Load(...); }
catch (FileLoadException ex) when (ex.Message.Contains("Could not parse merged config"))
{ _log.Error($"Config parse failed: {ex.Message}"); Config.RestoreDefaults(); /* or prompt user */ }

Prevention

When it happens

Trigger: Produced at Config_Static.cs:589 when JsonSerializer.Deserialize(mergedJson, jsonContext.Config) returns null. Reached at the end of config load after MergeJsonLayers — the merge produced a JSON document that deserializes to null.

Common situations: A hand-edited igconfig.json reduced to the literal `null`; a CLI override or admin layer that overwrote the whole object with null; MergeJsonLayers returning an empty byte array when all layers were null (e.g. first run with no default shipped); a corrupt default config shipped with the build; a JSON merge that produced `null` via deep override semantics.

Related errors


AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13). Data as JSON: /api/errors/bd43768bfa0db39d. Report an issue: GitHub.