stride3d/stride · error · NotImplementedException
Code upgrade for [ ] produced changes other than regular…
Error message
Code upgrade for [{projectChanges.NewProject.Name}] produced changes other than regular document text (added/removed docs, references, etc.); the runner persists changed .cs text only. What it means
After applying Roslyn upgrades, EnsureNoUnsupportedChanges verifies that the workspace produced only regular document text changes. If a rule also added/removed documents or changed project/metadata/analyzer references, the runner cannot persist those, so it throws NotImplementedException to prevent silent loss of changes.
Solutions
- Rewrite the upgrade rule to only modify text of existing documents
- Manually apply the reference/document additions the rule wanted, then re-run only text edits
- Split the upgrade: automated text edits via the runner, manual steps for references/new files
- If you own the runner, extend persistence to handle non-text changes
Defensive patterns
Strategy: try-catch
Validate before calling
// dry-run rule against a sample project and inspect the resulting changes
var changes = upgradeRule.GetChanges(sampleProject);
if (changes.AddedDocuments.Any() || changes.AddedProjects.Any())
logger.Warning("Rule produces non-text changes; runner will reject it."); Type guard
static bool IsTextOnly(ProjectChanges changes) =>
!changes.GetAddedDocuments().Any() && !changes.GetRemovedDocuments().Any() &&
!changes.GetAddedProjectReferences().Any() && !changes.GetRemovedProjectReferences().Any(); Try / catch
try
{
await RunUpgradesAsync(solution);
}
catch (NotImplementedException ex) when (ex.Message.Contains("produced changes other than regular document text"))
{
logger.Error($"Upgrade rule too broad, apply its reference/new-file steps manually: {ex.Message}");
} Prevention
- Write upgrade rules that only rewrite existing document text
- Handle dependency/reference changes as documented manual steps
- Dry-run custom rules against a sample project first
- Never add/remove documents inside an upgrade rule
When it happens
Trigger: RunAsync applies upgrades whose solution changes include added/removed documents, or added/removed project, metadata, or analyzer references on projectChanges.
Common situations: Custom upgrade rules that add new files or edit project references (e.g. adding NuGet/package references) instead of only rewriting existing .cs text; rules migrating APIs that require new dependency assemblies.
Related errors
- Code upgrade gated at
- Could not find project associated to asset
- SurfaceRotation ' ' is not supported on Direct3D presenters.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/fbcab5b660526795.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Assets/CodeUpgrade/RoslynCodeUpgradeRunner.cs:193
// anything else would need workspace.TryApplyChanges() to reach the .csproj, so fail loud instead of dropping it.
private static void EnsureNoUnsupportedChanges(ProjectChanges projectChanges)
{
if (projectChanges.GetAddedDocuments().Any()
|| projectChanges.GetRemovedDocuments().Any()
|| projectChanges.GetChangedAdditionalDocuments().Any()
|| projectChanges.GetAddedAdditionalDocuments().Any()
|| projectChanges.GetRemovedAdditionalDocuments().Any()
|| projectChanges.GetChangedAnalyzerConfigDocuments().Any()
|| projectChanges.GetAddedAnalyzerConfigDocuments().Any()
|| projectChanges.GetRemovedAnalyzerConfigDocuments().Any()
|| projectChanges.GetAddedMetadataReferences().Any()
|| projectChanges.GetRemovedMetadataReferences().Any()
|| projectChanges.GetAddedProjectReferences().Any()
|| projectChanges.GetRemovedProjectReferences().Any()
|| projectChanges.GetAddedAnalyzerReferences().Any()
|| projectChanges.GetRemovedAnalyzerReferences().Any())
{
throw new NotImplementedException(
$"Code upgrade for [{projectChanges.NewProject.Name}] produced changes other than regular document " +
"text (added/removed docs, references, etc.); the runner persists changed .cs text only.");
}
}
private static bool PathsEqual(string? a, string? b)
{
if (a is null || b is null)
return false;
return string.Equals(Path.GetFullPath(a), Path.GetFullPath(b), StringComparison.OrdinalIgnoreCase);
}
}
View on GitHub (pinned to 96fad776d2)