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
- Fix the legacyState property in the file to be a JSON object, or remove the property entirely (null is accepted).
- Delete the corrupt state/migration file and let the next deployment recreate it.
- 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
- Don't hand-edit migration state files; let the pipeline own the schema.
- If scripting edits, round-trip through System.Text.Json so property types stay correct.
- Keep the whole file from one Aspire version — don't mix schemas.
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
- ' ' must be a JSON string.
- ' ' must be a JSON string.
- ' ' must contain a JSON object.
- Cannot convert to boolean for key
- Deployment state must contain a JSON object.
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)