Fix #6466: make workflow checkpoint TypeId version-insensitive#6469
Open
saikir1994 wants to merge 1 commit into
Open
Fix #6466: make workflow checkpoint TypeId version-insensitive#6469saikir1994 wants to merge 1 commit into
saikir1994 wants to merge 1 commit into
Conversation
TypeId identity was derived from Assembly.FullName, which embeds Version, Culture, and PublicKeyToken. Any SDK version bump invalidated previously persisted checkpoints, causing restore to throw InvalidDataException. Compare and hash TypeId using only the simple assembly name plus the type full name. The stored AssemblyName field, public property, and ToString output are unchanged, so the serialized checkpoint shape and public API are preserved and legacy checkpoints remain matchable. Also fixes a latent second version-sensitivity in WorkflowSession.TryGetRequestEnvelope, where Type.GetType used the version-qualified assembly name; it now uses the simple name for robust resolution after upgrades.
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR makes TypeId comparisons independent of assembly version (and related qualifiers) to ensure checkpoints remain compatible across SDK versions, and updates type resolution to use the assembly simple name.
Changes:
- Normalize
TypeIdequality/hash/match behavior to ignore assembly version/culture/public key token. - Update
WorkflowSessionrequest envelope type resolution to use the normalized assembly simple name. - Add unit tests covering version-mismatch equality and dictionary lookup behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| dotnet/src/Microsoft.Agents.AI.Workflows/Checkpointing/TypeId.cs | Adds assembly-name normalization and switches equality/hash/match to use the simple assembly name. |
| dotnet/src/Microsoft.Agents.AI.Workflows/WorkflowSession.cs | Uses the normalized assembly simple name for Type.GetType resolution. |
| dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/TypeIdVersionMismatchTests.cs | Adds tests validating version-independent TypeId equality/matching and dictionary lookup. |
Comment on lines
+35
to
+45
| private static string NormalizeAssemblyName(string assemblyName) | ||
| { | ||
| try | ||
| { | ||
| return new AssemblyName(assemblyName).Name ?? assemblyName; | ||
| } | ||
| catch (Exception) | ||
| { | ||
| return assemblyName; | ||
| } | ||
| } |
| } | ||
|
|
||
| return this.AssemblyName == other.AssemblyName && this.TypeName == other.TypeName; | ||
| return this.AssemblySimpleName == other.AssemblySimpleName && this.TypeName == other.TypeName; |
|
|
||
| /// <inheritdoc /> | ||
| public override int GetHashCode() => HashCode.Combine(this.AssemblyName, this.TypeName); | ||
| public override int GetHashCode() => HashCode.Combine(this.AssemblySimpleName, this.TypeName); |
Comment on lines
+108
to
109
| return this.AssemblySimpleName == type.Assembly.GetName().Name | ||
| && this.TypeName == type.FullName; |
Comment on lines
+305
to
306
| Type? concreteType = Type.GetType($"{requestType.TypeName}, {requestType.AssemblySimpleName}", throwOnError: false); | ||
| if (concreteType is null || !typeof(IExternalRequestEnvelope).IsAssignableFrom(concreteType)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #6466.
Workflow checkpoint restore failed with
System.IO.InvalidDataException: The specified checkpoint is not compatible with the workflow associated with this runner.whenever the assembly version changed between the run that wrote a checkpoint and the run that restored it (i.e. after any package upgrade and redeploy), even when the workflow topology, executor IDs, and state shape were identical.Root cause
TypeIdidentity was derived fromAssembly.FullName, which embedsVersion,Culture, andPublicKeyToken:TypeIdis serialized into checkpoints and re-derived from the currently loaded assemblies on restore, so any version bump made the strings differ and invalidated every previously persisted checkpoint. The sameAssemblyNamecomparison also backsTypeId.Equals/GetHashCode, which matters becauseTypeIdis used as a dictionary key inMessageTypeTranslator,MessageRouter, and the executor yield-type set — so in-flight message type lookups would also fail across versions.Changes
TypeId— Comparison and hashing are now based on the simple assembly name (version-, culture-, and public-key-token-independent) plus the type full name:NormalizeAssemblyName(parses the simple name viaSystem.Reflection.AssemblyName, with a safe fallback to the raw value if it can't be parsed) and a lazily-cached internalAssemblySimpleName.Equals,GetHashCode, andIsMatch(Type)now use the simple assembly name.TypeId(Type)constructor, the publicAssemblyNameproperty, andToString()are unchanged — the serialized checkpoint shape and public API are preserved, and legacy (version-qualified) checkpoints remain matchable via normalization.WorkflowSession.TryGetRequestEnvelope— Fixes a latent second version-sensitivity whereType.GetType($"{TypeName}, {AssemblyName}")used the version-qualified assembly name (which can fail to resolve after an upgrade for strong-named assemblies). It now uses the simple name for robust resolution.Approach / compatibility
This is the most conservative fix: the stored
AssemblyNamevalue, the serialized JSON shape, and the publicAssemblyNameproperty are all unchanged. Only the comparison/hash/resolution paths are normalized. As a result:Tests
TypeIdVersionMismatchTests(7 tests) covering:IsMatch,Equals, andGetHashCodeignore assembly version.Dictionary<TypeId, T>lookups succeed across version forms (legacy full name vs. current simple name).Microsoft.Agents.AI.Workflows.UnitTestssuite passes: 652 passed, 0 failed (net10.0), including the existingJsonSerializationTests, checkpointing, and executor tests.