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
- Remove the asset from its current package first (currentPackage.Assets.Remove(item)), which clears ownership, then add it to the new package.
- 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.
- If this is a move operation, use the session/package APIs designed for moves rather than raw Add on two collections.
- 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
- Treat AssetItem as owned by exactly one package
- Clone (deep) when sharing assets across packages
- Use Remove before re-adding in move operations
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
- Cannot add an asset with an empty Id
- Asset location [ ] must be relative and not absolute (not…
- An asset [ ] with the same location [ ] is already…
- An asset with the same id
- Asset location [ ] cannot contain drive information
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)