stride3d/stride · error · ArgumentException

Cannot add an asset that is already added to another package

Error message

Cannot add an asset that is already added to another package

What it means

An AssetItem can only belong to one package at a time; its Package property is the owning back-reference. CheckCanAdd rejects an asset whose Package is already set to a different package, because adding it here would corrupt the single-owner invariant and the session-wide id uniqueness checks.

Solutions

  1. Remove the asset from its current package first (currentPackage.Assets.Remove(item)), which clears ownership, then add it to the new package.
  2. If you need the asset in both packages, deep-clone it (e.g. via AssetItem/Asset cloning with a new AssetId) instead of sharing the instance.
  3. If this is a move operation, use the session/package APIs designed for moves rather than raw Add on two collections.
  4. Check item.Package before adding and handle the already-owned case explicitly.

Example fix

// before
newPackage.Assets.Add(assetItem); // throws: asset belongs to oldPackage

// after
oldPackage.Assets.Remove(assetItem);
newPackage.Assets.Add(assetItem);
Defensive patterns

Strategy: validation

Validate before calling

if (item.Package != null && item.Package != package)
    item.Package.Assets.Remove(item);
package.Assets.Add(item);

Type guard

bool IsUnownedOrOwnedBy(AssetItem a, Package p) => a.Package == null || a.Package == p;

Try / catch

try { package.Assets.Add(item); }
catch (ArgumentException e) when (e.Message.Contains("another package"))
{ /* detach and retry, or deep-clone with a new id */ }

Prevention

When it happens

Trigger: Calling package.Assets.Add(item) where item.Package != null and item.Package != package — e.g. adding an asset loaded from another package file, or moving an asset between packages without detaching it first.

Common situations: Reusing one AssetItem object across multiple Package instances in a tool; merging two packages while sharing asset instances; copying assets between packages by reference instead of by deep clone.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/b8e744d879782593. Report an issue: GitHub.

Appendix: source

Thrown at sources/assets/Stride.Core.Assets/PackageAssetCollection.cs:330

        // TODO better handle interaction
        if (item == null)
        {
            throw new ArgumentNullException(nameof(item), "Cannot add an empty asset item reference");
        }

        if (registeredItems.Contains(item))
        {
            throw new ArgumentException("Asset already exist in this collection", nameof(item));
        }

        if (item.Id == AssetId.Empty)
        {
            throw new ArgumentException("Cannot add an asset with an empty Id", nameof(item));
        }

        if (item.Package != null && item.Package != Package)
        {
            throw new ArgumentException("Cannot add an asset that is already added to another package", nameof(item));
        }

        // Note: we ignore name collisions if asset is not referenceable
        var referenceable = item.Asset.GetType().GetCustomAttribute<AssetDescriptionAttribute>()?.Referenceable ?? true;

        // Namespaced packages root their locations /Namespace/...; creation paths author
        // unqualified locations, qualified here like the loaders do. Plain packages stay
        // relative-only (that reservation is what makes rooted URLs collision-free).
        // Detached packages (clones, pack-time copies) have no container: locations pass through.
        var location = item.Location;
        if (Package.Container is { } container)
        {
            if (container.AssetNamespace is not null)
            {
                item.Location = location = container.Qualify(location);
            }
            else if (location.IsAbsolute)
            {

View on GitHub (pinned to 96fad776d2)