dotnet/aspnetcore · error · InvalidOperationException
The static asset '{property.Value}' is already mapped to {va
Error message
The static asset '{property.Value}' is already mapped to {value.Url}. What it means
Thrown by the ResourceAssetCollection constructor. While indexing resources, it builds a label->asset map; if two distinct ResourceAsset entries declare the same "label" property value, the second one collides with the first. Labels must uniquely identify a content-specific URL, so a duplicate is an unrecoverable mapping conflict.
Source
Thrown at src/Components/Components/src/ResourceAssetCollection.cs:40
/// <summary>
/// Initializes a new instance of <see cref="ResourceAssetCollection"/>
/// </summary>
/// <param name="resources">The list of resources available.</param>
public ResourceAssetCollection(IReadOnlyList<ResourceAsset> resources)
{
var mappings = new Dictionary<string, ResourceAsset>(StringComparer.OrdinalIgnoreCase);
var contentSpecificUrls = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
_resources = resources;
foreach (var resource in resources)
{
foreach (var property in resource.Properties ?? [])
{
if (property.Name.Equals("label", StringComparison.OrdinalIgnoreCase))
{
if (mappings.TryGetValue(property.Value, out var value))
{
throw new InvalidOperationException($"The static asset '{property.Value}' is already mapped to {value.Url}.");
}
mappings[property.Value] = resource;
contentSpecificUrls.Add(resource.Url);
}
}
}
_uniqueUrlMappings = mappings.ToFrozenDictionary();
_contentSpecificUrls = contentSpecificUrls.ToFrozenSet();
}
/// <summary>
/// Gets the unique content-based URL for the specified static asset.
/// </summary>
/// <param name="key">The asset name.</param>
/// <returns>The unique URL if available, the same <paramref name="key"/> if not available.</returns>
public string this[string key] => _uniqueUrlMappings.TryGetValue(key, out var value) ? value.Url : key;
View on GitHub (pinned to 294cab2f9b)
Solutions
- Inspect the ResourceAsset list for duplicate "label" property values before constructing the collection.
- Regenerate the static-asset manifest (rebuild) so labels are unique.
- Dedupe the source list, keeping one ResourceAsset per label, or rename the conflicting labels.
Example fix
// before
var assets = new[] {
new ResourceAsset("/a.file", new[]{ new ResourceAssetProperty("label", "logo") }),
new ResourceAsset("/b.file", new[]{ new ResourceAssetProperty("label", "logo") }), // dup
};
var col = new ResourceAssetCollection(assets);
// after
var byLabel = assets
.SelectMany(a => (a.Properties ?? Array.Empty<ResourceAssetProperty>())
.Where(p => p.Name.Equals("label", StringComparison.OrdinalIgnoreCase))
.Select(p => (p.Value, a)))
.GroupBy(x => x.Value, StringComparer.OrdinalIgnoreCase);
foreach (var g in byLabel) if (g.Count() > 1) throw new InvalidOperationException($"dup label {g.Key}");
var col = new ResourceAssetCollection(assets); Defensive patterns
Strategy: validation
Validate before calling
// Validate the resource list for duplicate labels before constructing the collection.
static bool HasDuplicateLabels(IReadOnlyList<ResourceAsset> assets) {
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var a in assets)
foreach (var p in a.Properties ?? Array.Empty<ResourceAssetProperty>())
if (p.Name.Equals("label", StringComparison.OrdinalIgnoreCase)
&& !seen.Add(p.Value)) return true;
return false;
} Try / catch
try { _assets = new ResourceAssetCollection(list); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already mapped")) {
_logger.LogError(ex, "Static asset manifest has duplicate labels; regenerating build output.");
_assets = ResourceAssetCollection.Empty; // fallback only if appropriate
} Prevention
- Regenerate the static-asset manifest when source assets change so labels stay unique.
- Run a duplicate-label check over your ResourceAsset list in a startup/test step.
- Avoid manually merging two asset manifests; rebuild from a single source.
When it happens
Trigger: Constructing a ResourceAssetCollection (e.g., from the static-asset manifest produced at build time) where two resources expose Properties with Name=="label" and the same Value. Common with customized asset pipelines that emit duplicate fingerprinted labels.
Common situations: Two source files producing assets with identical logical labels after a rename/copy; a build manifest generated twice and concatenated; a manual/incorrect ResourceAsset list passed to a test or service registration.
Related errors
- The event '${eventName}' is already registered.
- EqualTo validator requires a non-empty "other" parameter.
- FileExtensions validator requires a non-empty "extensions" p
- Range validator requires at least one of "min" or "max" para
- regex validator requires a non-empty "pattern" parameter.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/0ff7a22da64c0ccc.
Report an issue: GitHub.