{"record":{"id":"c3b84a455a2da436","repo":"stride3d/stride","slug":"the-relativepath-argument-is-null-or-empty","errorCode":null,"errorMessage":"The relativePath argument is null or empty","messagePattern":"The relativePath argument is null or empty","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/assets/Stride.Core.Assets/Compiler/AssetCompilerBase.cs","lineNumber":85,"sourceCode":"    /// <summary>\n    /// Compiles the asset from the specified package.\n    /// </summary>\n    /// <param name=\"context\">The context to use to compile the asset.</param>\n    /// <param name=\"assetItem\">The asset to compile</param>\n    /// <param name=\"targetUrlInStorage\">The absolute URL to the asset, relative to the storage.</param>\n    /// <param name=\"result\">The result where the commands and logs should be output.</param>\n    protected abstract void Prepare(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result);\n\n    /// <summary>\n    /// Returns the absolute path on the disk of an <see cref=\"UFile\"/> that is relative to the asset location.\n    /// </summary>\n    /// <param name=\"assetItem\">The asset on which is based the relative path.</param>\n    /// <param name=\"relativePath\">The path relative to the asset path that must be converted to an absolute path.</param>\n    /// <returns>The absolute path on the disk of the <paramref name=\"relativePath\"/> argument.</returns>\n    /// <exception cref=\"ArgumentException\">The <paramref name=\"relativePath\"/> argument is a null or empty <see cref=\"UFile\"/>.</exception>\n    protected static UFile GetAbsolutePath(AssetItem assetItem, UFile relativePath)\n    {\n        if (string.IsNullOrEmpty(relativePath)) throw new ArgumentException(\"The relativePath argument is null or empty\");\n        var assetDirectory = assetItem.FullPath.GetParent();\n        var assetSource = UPath.Combine(assetDirectory, relativePath);\n        return assetSource;\n    }\n\n    /// <summary>\n    /// Ensures that the sources of an <see cref=\"Asset\"/> exist.\n    /// </summary>\n    /// <param name=\"result\">The <see cref=\"AssetCompilerResult\"/> in which to output log of potential errors.</param>\n    /// <param name=\"assetItem\">The asset to check.</param>\n    /// <returns><c>true</c> if the source file exists, <c>false</c> otherwise.</returns>\n    /// <exception cref=\"ArgumentNullException\">Any of the argument is <c>null</c>.</exception>\n    private static bool EnsureSourcesExist(AssetCompilerResult result, AssetItem assetItem)\n    {\n        ArgumentNullException.ThrowIfNull(result);\n        ArgumentNullException.ThrowIfNull(assetItem);\n\n        var collector = new SourceFilesCollector();","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/assets/Stride.Core.Assets/Compiler/AssetCompilerBase.cs#L67-L103","documentation":"The protected helper GetAbsolutePath combines a relative path with the parent directory of the asset's FullPath to produce an absolute on-disk path. It guards against a null or empty UFile argument by throwing ArgumentException, since combining an empty path is meaningless.","triggerScenarios":"Calling GetAbsolutePath(assetItem, relativePath) from a custom asset compiler with an uninitialized or empty UFile — e.g. a source/import path field on the asset was never set (default UFile is empty string).","commonSituations":"Asset YAML missing the expected source path field so it deserializes to an empty UFile; user cleared the 'Source' field in the editor; a compiler reading the wrong (unused) property as its relative path.","solutions":["Ensure the asset's source path property (e.g. Yolo/Source) is set before compilation.","Guard with string.IsNullOrEmpty(relativePath) in the compiler and log a proper error instead of passing it through.","Fix asset deserialization so missing path fields get a default or are reported as a validation error.","If the path should be optional, skip GetAbsolutePath when empty instead of calling it."],"exampleFix":"// before\nvar abs = GetAbsolutePath(assetItem, asset.Source); // Source is empty UFile\n// after\nif (!string.IsNullOrEmpty(asset.Source))\n{\n    var abs = GetAbsolutePath(assetItem, asset.Source);\n}\nelse\n{\n    logger.Error($\"Asset {assetItem.Location} is missing its source path.\");\n}","handlingStrategy":"validation","validationCode":"if (string.IsNullOrEmpty(asset.Source))\n{\n    logger.Error($\"Asset {assetItem.Location} has no source path set.\");\n    return;\n}\nvar abs = GetAbsolutePath(assetItem, asset.Source);","typeGuard":"static bool HasSourcePath(UFile relativePath) => !string.IsNullOrEmpty(relativePath);","tryCatchPattern":"try\n{\n    var abs = GetAbsolutePath(assetItem, asset.Source);\n}\ncatch (ArgumentException ex)\n{\n    logger.Error($\"Missing source path for asset {assetItem.Location}: {ex.Message}\");\n}","preventionTips":["Make source path fields required in asset templates and the editor.","Validate asset fields (source paths not empty) during asset import/save.","When deserializing, treat an empty expected-path field as an error instead of silently continuing."],"tags":["null-argument","path","asset-compilation","argument-validation"],"backgroundTag":"null-argument","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"}