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

  1. Inspect the ResourceAsset list for duplicate "label" property values before constructing the collection.
  2. Regenerate the static-asset manifest (rebuild) so labels are unique.
  3. 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

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


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/0ff7a22da64c0ccc. Report an issue: GitHub.