Fix template load failure when template.json contains duplicate JSON property keys#10048
Closed
Fix template load failure when template.json contains duplicate JSON property keys#10048
Conversation
In .NET 10+, JsonObject.InitializeDictionary() throws ArgumentException when duplicate property keys exist in JSON. The PropertiesOf() method called .ToList() on JsonObject which triggered Count -> InitializeDictionary() via the List<T>(ICollection<T>) constructor. Fix: wrap the ToList() call in a try/catch for ArgumentException and fall back to JsonDocument-based enumeration which tolerates duplicate keys. JsonObject.WriteTo() safely returns the original JSON via its underlying JsonElement even after a failed initialization. Fixes: MAUI templates failing to load with 'An item with the same key has already been added. Key: empty' error. Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/templating/sessions/71aa8b90-cc61-4d4e-92eb-2c3c821d5d5c
Copilot
AI
changed the title
[WIP] Fix error loading template from nupkg file in CLI
Fix template load failure when template.json contains duplicate JSON property keys
Mar 25, 2026
Member
|
The original issue was a case collision to we'll prefer https://github.com/dotnet/templating/pull/10049/changes |
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.
Problem
Templates (notably MAUI) fail to load with
ArgumentException: An item with the same key has already been added. Key: emptyon .NET 10+ SDKs. The MAUItemplate.jsonhas duplicate"empty"keys in the"forms"section. In .NET 10+,JsonObjectswitched toOrderedDictionary<TKey,TValue>with lazy initialization —JsonObject.CounttriggersInitializeDictionary(), which throws on duplicates.JExtensions.PropertiesOf()calledjObj.ToList(), andList<T>(ICollection<T>)callsCountto pre-size the list, hitting this path.Solution
src/Shared/JExtensions.cs: Replace the barejObj.ToList()calls inPropertiesOf()with aGetObjectProperties()helper that catchesArgumentExceptionand falls back toGetObjectPropertiesViaDocument(). The fallback serializes viaJsonObject.ToJsonString()(safe becauseWriteTo()uses the underlyingJsonElementwhen_dictionaryis null, even after a failed init) and re-enumerates withJsonDocumentwhich tolerates duplicate keys.test/.../TemplateConfigTests/GenericTests.cs: Two regression tests covering duplicate keys in"forms"and"symbols"sections.Checks:
Original prompt
This section details on the original issue you should resolve
<issue_title>[NETSDKE2E][Regression]Error: Failed to load template from "C:\xxx\microsoft.maui.templates.net10.10.0.20.nupkg(/content/templates/maui-blazor-solution/.template.config/template.json)" displays when running command in CLI for the first time.</issue_title>
<issue_description>RGRESSION INFO
not repro on VS 18.6 Insiders [11617.261.main] + 11.0.100-preview.3.26166.111 (runtime- 11.0.0-preview.3.26166.111)
not repro in CLI when only installed Insiders VS 18.6 [11618.325.main]
INSTALL STEPS
Insiders VS 18.6 [11618.325.main] + 11.0.100-preview.3.26168.106 (runtime- 11.0.100-preview.3.26168.106) on win-x64
REPRO STEPS
1.In CLI, run the dotnet command for the first time, e.g dotnet new sln
ACTUAL

sln is created successfully,but below error happens
Error: Failed to load template from "C:\Program Files\dotnet\template-packs\microsoft.maui.templates.net10.10.0.20.nupkg(/content/templates/maui-blazor-solution/.template.config/template.json)".
Details: System.ArgumentException: An item with the same key has already been added. Key: empty (Parameter 'key')
at System.Collections.ThrowHelper.ThrowDuplicateKey[TKey](TKey key)
at System.Collections.Generic.OrderedDictionary
2.TryInsert(Int32 index, TKey key, TValue value, InsertionBehavior behavior, Int32& keyIndex) at System.Collections.Generic.OrderedDictionary2.Add(TKey key, TValue value)at System.Text.Json.Nodes.JsonObject.InitializeDictionary()
at System.Text.Json.Nodes.JsonObject.get_Count()
at System.Collections.Generic.List
1..ctor(IEnumerable1 collection)at System.Linq.Enumerable.ToList[TSource](IEnumerable
1 source) at Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel.TemplateConfigModel..ctor(JsonObject source, ILogger logger, String baselineName) at Microsoft.TemplateEngine.Orchestrator.RunnableProjects.DirectoryBasedTemplate..ctor(IEngineEnvironmentSettings settings, IGenerator generator, IFile templateFile, String baselineName) at Microsoft.TemplateEngine.Orchestrator.RunnableProjects.RunnableProjectGenerator.GetTemplatesFromMountPointInternalAsync(IMountPoint source, CancellationToken cancellationToken) Error: Failed to load template from "C:\Program Files\dotnet\template-packs\microsoft.maui.templates.net10.10.0.20.nupkg(/content/templates/maui-blazor/.template.config/template.json)". Details: System.ArgumentException: An item with the same key has already been added. Key: empty (Parameter 'key') at System.Collections.ThrowHelper.ThrowDuplicateKey[TKey](TKey key) at System.Collections.Generic.OrderedDictionary2.TryInsert(Int32 index, TKey key, TValue value, InsertionBehavior behavior, Int32& keyIndex)at System.Collections.Generic.OrderedDictionary
2.Add(TKey key, TValue value) at System.Text.Json.Nodes.JsonObject.InitializeDictionary() at System.Text.Json.Nodes.JsonObject.get_Count() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)at Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel.TemplateConfigModel..ctor(JsonObject source, ILogger logger, String baselineName)
at Microsoft.TemplateEngine.Orchestrator.RunnableProjects.DirectoryBasedTemplate..ctor(IEngineEnvironmentSettings settings, IGenerator generator, IFile templateFile, String baselineName)
at Microsoft.TemplateEngine.Orchestrator.RunnableProjects.RunnableProjectGenerator.GetTemplatesFromMountPointInternalAsync(IMountPoint source, CancellationToken cancellationToken)
Expected Result:
sln is created successfully without any erros
Note:
1.We don't meet it in CLI when only installing SDK
2.it not happens when running command in CLI for the second time</issue_description>
<agent_instructions>Can you review the code and determine if this is something hte template engine should fix or something in the authoring of the maui templates? From the description, it looks like an issue if you install a newer sdk and older SDK SxS and the new SDK finds a duplicate template between the new and old SDKS.</agent_instructions>
Comments on the Issue (you are @copilot in this section)
@balachir @marcpopMSFT is this an issue in the .NET SDK that needs to be looked at for .NET 11 P3? From [Nicole's scenario above](https://github.com//issues/10047#issuecomment-4128056053), this reproduces when only .NET SDK is installed and even the install of VS is not necessary. @marcpopMSFT Moving to templating because that's where the callstack is from.🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.