microsoft/aspire · error · InvalidDataException

' ' must be a JSON object.

Error message

'{LegacyStateProperty}' must be a JSON object.

What it means

When reading the migration state record, the manager requires the 'legacyState' property to be either absent/null or a JsonObject; any other JSON type (array, string, number) throws InvalidDataException. This is part of validating the legacy-to-current state-file migration snapshot.

Solutions

  1. Fix the legacyState property in the file to be a JSON object, or remove the property entirely (null is accepted).
  2. Delete the corrupt state/migration file and let the next deployment recreate it.
  3. Restore the file from a known-good backup.

Example fix

// before (state file)
{ "legacyState": "not-an-object" }
// after
{ "legacyState": { "key": "value" } }
Defensive patterns

Strategy: validation

Validate before calling

// Validate before handing the file to the manager
if (migrationState["legacyState"] is not (null or JsonObject))
{
    throw new InvalidDataException("legacyState must be a JSON object or absent.");
}

Type guard

static bool HasValidLegacyState(JsonObject migrationState) =>
    migrationState["legacyState"] is null or JsonObject;

Try / catch

try { await manager.LoadStateAsync(ct); }
catch (InvalidDataException ex) when (ex.Message.Contains("legacyState") && ex.Message.Contains("JSON object"))
{
    // back up and regenerate the state file
    File.Move(statePath, statePath + ".corrupt", overwrite: true);
}

Prevention

When it happens

Trigger: Loading a migration/state file where the legacyState property holds a non-object JSON value — e.g. after a hand edit, a bad migration write, or corruption.

Common situations: Manual editing of the migration state file; an interrupted or buggy write of the legacy snapshot; version skew between Aspire versions that changed the file layout.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/31f1c195c0ecfd9f. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting/Pipelines/Internal/FileDeploymentStateManager.cs:753

        return ParseMigrationState(migrationState);
    }

    private static MigrationState LoadMigrationStateFile(string canonicalStatePath)
    {
        var migrationStatePath = GetMigrationStatePath(canonicalStatePath);
        return File.Exists(migrationStatePath)
            ? ParseMigrationState(LoadStateFile(migrationStatePath))
            : new(false, [], [], null);
    }

    private static MigrationState ParseMigrationState(JsonObject migrationState)
    {
        var legacyFallbackDisabled = migrationState[LegacyFallbackDisabledProperty]?.GetValue<bool>() ?? false;
        var legacyStateSnapshot = migrationState[LegacyStateProperty] switch
        {
            null => [],
            JsonObject legacyState => legacyState,
            _ => throw new InvalidDataException($"'{LegacyStateProperty}' must be a JSON object.")
        };
        var claimedSectionNames = migrationState[ClaimedSectionsProperty] switch
        {
            null => [],
            JsonValue claimedSectionsValue => ParseClaimedSectionNames(claimedSectionsValue),
            _ => throw new InvalidDataException($"'{ClaimedSectionsProperty}' must be a JSON string.")
        };
        var currentState = migrationState[CurrentStateProperty] switch
        {
            null => null,
            JsonValue stateValue => JsonNode.Parse(stateValue.GetValue<string>())?.AsObject()
                ?? throw new InvalidDataException($"'{CurrentStateProperty}' must contain a JSON object."),
            _ => throw new InvalidDataException($"'{CurrentStateProperty}' must be a JSON string.")
        };

        return new(legacyFallbackDisabled, legacyStateSnapshot, claimedSectionNames, currentState);
    }

View on GitHub (pinned to 25830f84bd)