{"record":{"id":"2e095298badfca2d","repo":"stride3d/stride","slug":"asset-location-0-cannot-start-with-relative","errorCode":null,"errorMessage":"Asset location [{0}] cannot start with relative '..'","messagePattern":"Asset location \\[(.+?)\\] cannot start with relative '\\.\\.'","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/assets/Stride.Core.Assets/PackageAssetCollection.cs","lineNumber":370,"sourceCode":"\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\n        if (location.GetDirectory()?.StartsWith(\"..\", StringComparison.Ordinal) == true)\n        {\n            throw new ArgumentException(\"Asset location [{0}] cannot start with relative '..'\".ToFormat(location), nameof(item));\n        }\n\n        // Double check that this asset is not already stored in another package for this session\n        if (Package.Session != null)\n        {\n            foreach (var otherPackage in Package.Session.Packages)\n            {\n                if (otherPackage != Package)\n                {\n                    if (otherPackage.Assets.ContainsById(item.Id))\n                    {\n                        throw new ArgumentException(\"Cannot add the asset [{0}] [{1}] to package [{2}] [{3}]: it is already in package [{4}] [{5}] in the current session\".ToFormat(item.Id, item.Location, Package.Meta.Name, Package.FullPath, otherPackage.Meta.Name, otherPackage.FullPath));\n                    }\n                }\n            }\n        }\n    }\n","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/assets/Stride.Core.Assets/PackageAssetCollection.cs#L352-L388","documentation":"Asset locations are rooted at the package root; a directory component starting with '..' would escape that root. CheckCanAdd rejects such locations because escaped locations break the package-relative addressing model and can collide with or leak into sibling packages.","triggerScenarios":"Calling package.Assets.Add(item) where the location's directory begins with '..' (e.g. '../Shared/asset') and the container has no AssetNamespace that would re-root it.","commonSituations":"Computing relative paths with '..' segments when the asset file sits outside the current package folder; string-joining paths with Parent/.. navigation; moving an asset to a location that points outside the package.","solutions":["Relocate the asset so its location is inside the package, and pass a location without leading '..' segments.","If the asset genuinely belongs to shared content, put it in the package that actually roots it and reference it from there.","Normalize the path (resolve '..' against the package root) and recompute a clean relative location.","Validate with !(location.GetDirectory()?.StartsWith(\"..\") == true) before Add."],"exampleFix":"// before\nvar item = new AssetItem(new UFile(\"../Shared/sword\"), asset);\npackage.Assets.Add(item); // throws: starts with '..'\n\n// after\nvar item = new AssetItem(new UFile(\"Shared/sword\"), asset);\npackage.Assets.Add(item);","handlingStrategy":"validation","validationCode":"if (item.Location.GetDirectory()?.StartsWith(\"..\") == true)\n    item.Location = NormalizeInsidePackage(item.Location, package);\npackage.Assets.Add(item);","typeGuard":"bool IsInsidePackage(UFile loc) => loc.GetDirectory()?.StartsWith(\"..\", StringComparison.Ordinal) != true;","tryCatchPattern":"try { package.Assets.Add(item); }\ncatch (ArgumentException e) when (e.Message.Contains(\"relative '..'\"))\n{ /* normalize the location or move the asset */ }","preventionTips":["Resolve '..' segments before creating AssetItem","Keep assets physically inside their package folder","Use the container's path APIs instead of manual string joins"],"tags":["assets","paths","argument-exception"],"backgroundTag":"path-traversal-blocked","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"}