{"record":{"id":"61706c0075583852","repo":"stride3d/stride","slug":"cannot-add-an-asset-with-an-empty-id","errorCode":null,"errorMessage":"Cannot add an asset with an empty Id","messagePattern":"Cannot add an asset with an empty Id","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/assets/Stride.Core.Assets/PackageAssetCollection.cs","lineNumber":325,"sourceCode":"    /// or\n    /// Asset location [{0}] cannot start with relative '..'.ToFormat(location);item\n    /// </exception>\n    public void CheckCanAdd(AssetItem item)\n    {\n        // TODO better handle interaction\n        if (item == null)\n        {\n            throw new ArgumentNullException(nameof(item), \"Cannot add an empty asset item reference\");\n        }\n\n        if (registeredItems.Contains(item))\n        {\n            throw new ArgumentException(\"Asset already exist in this collection\", nameof(item));\n        }\n\n        if (item.Id == AssetId.Empty)\n        {\n            throw new ArgumentException(\"Cannot add an asset with an empty Id\", nameof(item));\n        }\n\n        if (item.Package != null && item.Package != Package)\n        {\n            throw new ArgumentException(\"Cannot add an asset that is already added to another package\", nameof(item));\n        }\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)","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/assets/Stride.Core.Assets/PackageAssetCollection.cs#L307-L343","documentation":"PackageAssetCollection.CheckCanAdd validates every asset before it is inserted into a package's asset collection. Every asset must carry a non-empty AssetId because the collection indexes assets by id (mapIdToPath) and serialized references resolve through it. An asset with AssetId.Empty cannot be referenced or tracked, so the collection refuses it with this ArgumentException.","triggerScenarios":"Calling Package.Assets.Add(item) (or any Add overload that routes through CheckCanAdd) with an asset whose Id property equals AssetId.Empty — e.g. a manually constructed AssetItem whose Id was never generated, or a deserialized asset that lost its id.","commonSituations":"Creating an AssetItem with 'new AssetItem { ... }' and forgetting to assign Id = Guid.NewGuid() (or AssetId.New()); hand-editing or round-tripping YAML that dropped the Id field; copying asset properties onto a fresh instance without copying the id.","solutions":["Assign a fresh id before adding: asset.Id = AssetId.New() (or Guid.NewGuid()).","If the asset came from deserialization, verify the Id field is present and non-empty in the source file.","For clone scenarios, copy the original asset's Id, or generate a new one intentionally if the clone is a separate asset.","Wrap the Add call in a check: if (item.Id == AssetId.Empty) regenerate the id before adding."],"exampleFix":"// before\nvar asset = new AssetItem(location, myAsset);\npackage.Assets.Add(asset); // throws: empty Id\n\n// after\nvar asset = new AssetItem(location, myAsset) { Id = AssetId.New() };\npackage.Assets.Add(asset);","handlingStrategy":"validation","validationCode":"if (item.Id == AssetId.Empty)\n    item.Id = AssetId.New();\npackage.Assets.Add(item);","typeGuard":"bool HasValidId(AssetItem a) => a.Id != AssetId.Empty;","tryCatchPattern":"try { package.Assets.Add(item); }\ncatch (ArgumentException e) when (e.Message.Contains(\"empty Id\"))\n{ item.Id = AssetId.New(); package.Assets.Add(item); }","preventionTips":["Always construct AssetItem via helpers that assign AssetId.New()","Never hand-edit Id fields in serialized asset files","After deserialization, assert ids are non-empty before inserting into collections"],"tags":["assets","validation","argument-exception"],"backgroundTag":"empty-required-field","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"}