stride3d/stride · error · ArgumentException

Asset location [ ] must be relative and not absolute (not…

Error message

Asset location [{0}] must be relative and not absolute (not start with '/')

What it means

Asset locations must be package-relative. When the container has no AssetNamespace, CheckCanAdd rejects absolute locations (those starting with '/'), because absolute paths break the package-relative addressing model used by references and mounting.

Solutions

  1. Strip the leading '/' and pass a relative location, e.g. 'Assets/sword'.
  2. If the asset lives in a namespaced package, ensure the container's AssetNamespace is set so the location gets qualified automatically.
  3. Normalize the path before Add: use UFile/UDirectory APIs to convert absolute to relative paths against the package root.
  4. Validate with !location.IsAbsolute before calling Add.

Example fix

// before
var item = new AssetItem(new UFile("/Assets/sword"), asset);
package.Assets.Add(item); // throws: absolute location

// after
var item = new AssetItem(new UFile("Assets/sword"), asset);
package.Assets.Add(item);
Defensive patterns

Strategy: validation

Validate before calling

if (item.Location.IsAbsolute)
    item.Location = MakeRelativeToPackage(item.Location, package);
package.Assets.Add(item);

Type guard

bool IsRelativeLocation(UFile loc) => !loc.IsAbsolute;

Try / catch

try { package.Assets.Add(item); }
catch (ArgumentException e) when (e.Message.Contains("must be relative"))
{ /* normalize location to relative and retry */ }

Prevention

When it happens

Trigger: Calling package.Assets.Add(item) where item.Location.IsAbsolute (starts with '/') and the package/container does not define an AssetNamespace that would qualify the location. Note: when a namespace exists the location is auto-qualified instead of thrown.

Common situations: Building a location string like "/MyGame/Assets/sword" from a virtual file system path and passing it to Add; copying locations from mount paths or URLs instead of package-relative paths.

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/3e8b0f7adb1c6392. Report an issue: GitHub.

Appendix: source

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

        }

        // 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)
            {
                throw new ArgumentException("Asset location [{0}] must be relative and not absolute (not start with '/')".ToFormat(location), nameof(item));
            }
        }

        if (referenceable && mapPathToId.ContainsKey(location))
        {
            throw new ArgumentException("An asset [{0}] with the same location [{1}] is already registered ".ToFormat(mapPathToId[location], location.GetDirectoryAndFileName()), nameof(item));
        }

        if (mapIdToPath.ContainsKey(item.Id))
        {
            throw new ArgumentException("An asset with the same id [{0}] is already registered with the location [{1}]".ToFormat(item.Id, location.GetDirectoryAndFileName()), nameof(item));
        }

        if (location.HasDrive)
        {
            throw new ArgumentException("Asset location [{0}] cannot contain drive information".ToFormat(location), nameof(item));
        }

View on GitHub (pinned to 96fad776d2)