stride3d/stride · error · InvalidOperationException

Asset returned by CreateAssets has no location. Use…

Error message

Asset returned by CreateAssets has no location. Use GenerateLocation to generate the location for each asset.

What it means

AssetTemplateGenerator.Run adds each asset produced by CreateAssets to the target package and requires every AssetItem to have a non-empty Location so unique names can be computed. An asset with an empty Location indicates the generator forgot to call GenerateLocation, so Run throws InvalidOperationException.

Solutions

  1. In CreateAssets, wrap each created asset with GenerateLocation(parameters) before yielding the AssetItem
  2. Ensure the generated location string is non-empty (factory created a valid asset with a default name)
  3. Inspect your custom generator's CreateAssets override; the base generator already calls GenerateLocation, so avoid bypassing it

Example fix

// before
yield return new AssetItem(string.Empty, asset);
// after
yield return new AssetItem(GenerateLocation(parameters), asset);
Defensive patterns

Strategy: validation

Validate before calling

foreach (var item in CreateAssets(parameters))
    if (string.IsNullOrEmpty(item.Location)) throw new InvalidOperationException("Asset item has no location");

Type guard

bool HasLocation(AssetItem a) => !string.IsNullOrEmpty(a.Location);

Try / catch

try { generator.Run(parameters, assets); }
catch (InvalidOperationException) { // surface 'missing location' as a template-authoring bug
}

Prevention

When it happens

Trigger: A custom AssetTemplateGenerator overrides CreateAssets and returns AssetItem instances constructed without a location (e.g. new AssetItem(asset) with empty string/null location) instead of using GenerateLocation(parameters).

Common situations: Third-party template generator implementations copied from outdated samples; refactoring CreateAssets to build AssetItems directly instead of through the base-class helper.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/1376060a2b7f88cc. Report an issue: GitHub.

Appendix: source

Thrown at sources/editor/Stride.Assets.Presentation/Templates/AssetTemplateGenerator.cs:44

            parameters.Validate();
            return PrepareAssetCreation(parameters);
        }

        public sealed override bool Run(AssetTemplateGeneratorParameters parameters)
        {
            var assets = CreateAssets(parameters)?.ToList();
            if (assets == null)
            {
                parameters.Logger.Error("No asset created by the asset factory.");
                return false;
            }

            // Step one: add assets to package with proper unique name
            var newAssets = new Dictionary<AssetId, AssetItem>();
            foreach (var asset in assets)
            {
                if (string.IsNullOrEmpty(asset.Location))
                    throw new InvalidOperationException($"Asset returned by {nameof(CreateAssets)} has no location. Use {nameof(GenerateLocation)} to generate the location for each asset.");

                // Ensure unicity of names amongst package
                var name = NamingHelper.ComputeNewName(asset.Location, x => parameters.Package.Assets.Find(x) != null, "{0}_{1}");
                var item = new AssetItem(name, asset.Asset);

                try
                {
                    parameters.Package.Assets.Add(item);
                    // Ensure the dirty flag is properly set to refresh the dependency manager
                    item.IsDirty = true;
                }
                catch (Exception ex)
                {
                    parameters.Logger.Error("Failed to create new asset from template.", ex);
                    return false;
                }
                newAssets.Add(item.Id, item);
            }

View on GitHub (pinned to 96fad776d2)