{"record":{"id":"3e8b0f7adb1c6392","repo":"stride3d/stride","slug":"asset-location-0-must-be-relative-and-not-absolute-not-start","errorCode":null,"errorMessage":"Asset location [{0}] must be relative and not absolute (not start with '/')","messagePattern":"Asset location \\[(.+?)\\] must be relative and not absolute \\(not start with '/'\\)","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/assets/Stride.Core.Assets/PackageAssetCollection.cs","lineNumber":349,"sourceCode":"        }\n\n        // Note: we ignore name collisions if asset is not referenceable\n        var referenceable = item.Asset.GetType().GetCustomAttribute<AssetDescriptionAttribute>()?.Referenceable ?? true;\n\n        // Namespaced packages root their locations /Namespace/...; creation paths author\n        // unqualified locations, qualified here like the loaders do. Plain packages stay\n        // relative-only (that reservation is what makes rooted URLs collision-free).\n        // Detached packages (clones, pack-time copies) have no container: locations pass through.\n        var location = item.Location;\n        if (Package.Container is { } container)\n        {\n            if (container.AssetNamespace is not null)\n            {\n                item.Location = location = container.Qualify(location);\n            }\n            else if (location.IsAbsolute)\n            {\n                throw new ArgumentException(\"Asset location [{0}] must be relative and not absolute (not start with '/')\".ToFormat(location), nameof(item));\n            }\n        }\n\n        if (referenceable && mapPathToId.ContainsKey(location))\n        {\n            throw new ArgumentException(\"An asset [{0}] with the same location [{1}] is already registered \".ToFormat(mapPathToId[location], location.GetDirectoryAndFileName()), nameof(item));\n        }\n\n        if (mapIdToPath.ContainsKey(item.Id))\n        {\n            throw new ArgumentException(\"An asset with the same id [{0}] is already registered with the location [{1}]\".ToFormat(item.Id, location.GetDirectoryAndFileName()), nameof(item));\n        }\n\n        if (location.HasDrive)\n        {\n            throw new ArgumentException(\"Asset location [{0}] cannot contain drive information\".ToFormat(location), nameof(item));\n        }\n","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/assets/Stride.Core.Assets/PackageAssetCollection.cs#L331-L367","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Strip the leading '/' and pass a relative location, e.g. 'Assets/sword'.","If the asset lives in a namespaced package, ensure the container's AssetNamespace is set so the location gets qualified automatically.","Normalize the path before Add: use UFile/UDirectory APIs to convert absolute to relative paths against the package root.","Validate with !location.IsAbsolute before calling Add."],"exampleFix":"// before\nvar item = new AssetItem(new UFile(\"/Assets/sword\"), asset);\npackage.Assets.Add(item); // throws: absolute location\n\n// after\nvar item = new AssetItem(new UFile(\"Assets/sword\"), asset);\npackage.Assets.Add(item);","handlingStrategy":"validation","validationCode":"if (item.Location.IsAbsolute)\n    item.Location = MakeRelativeToPackage(item.Location, package);\npackage.Assets.Add(item);","typeGuard":"bool IsRelativeLocation(UFile loc) => !loc.IsAbsolute;","tryCatchPattern":"try { package.Assets.Add(item); }\ncatch (ArgumentException e) when (e.Message.Contains(\"must be relative\"))\n{ /* normalize location to relative and retry */ }","preventionTips":["Store locations as package-relative virtual paths only","Never pass absolute/vfs mount paths to Add","Qualify through the container API when namespaces are in play"],"tags":["assets","paths","argument-exception"],"backgroundTag":"invalid-argument-value","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}