{"record":{"id":"d0952cf3ffaefb27","repo":"dotnet/reactive","slug":"template-csproj-path-should-be-absolute","errorCode":null,"errorMessage":"Template csproj path should be absolute","messagePattern":"Template csproj path should be absolute","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Test/Gauntlet/RxGauntlet.Common/Build/ComponentBuilder.cs","lineNumber":76,"sourceCode":"            [\n                (\"DynamicallyBuiltPackages\", LocalNuGetPackageFolderPath),\n                ..(additionalPackageSources ?? [])\n            ];\n\n        (string projectTemplateFileName, ModifiedProjectClone project) = CreateModifiedProjectClone(\n            appBuildTempFolderName, templateCsProj, modifyProjectFile, packageSourcesIncludingDynamicallyBuiltPackages);\n\n        return await project.RunDotnetBuild(projectTemplateFileName);\n    }\n\n    private (string ProjectTemplateFileName, ModifiedProjectClone ProjectClone) CreateModifiedProjectClone(\n        string tempParentFolderName,\n        string templateCsProj,\n        Action<ProjectFileRewriter> modifyProjectFile,\n        (string FeedName, string FeedLocation)[]? additionalPackageSources)\n    {\n        string projectTemplateFolder = Path.GetDirectoryName(templateCsProj)\n            ?? throw new ArgumentException(\"Template csproj path should be absolute\", nameof(templateCsProj));\n        string projectTemplateFileName = Path.GetFileName(templateCsProj)\n            ?? throw new ArgumentException(\"Template csproj path should refer to a file, not a directory\", nameof(templateCsProj));\n        var projectClone = ModifiedProjectClone.Create(\n            projectTemplateFolder,\n            tempParentFolderName,\n            modifyProjectFile,\n            additionalPackageSources);\n        _projectClones.Add(projectClone);\n\n        return (projectTemplateFileName, projectClone);\n    }\n\n    public void Dispose()\n    {\n        foreach (ModifiedProjectClone clone in _projectClones)\n        {\n            clone.Dispose();\n        }","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Test/Gauntlet/RxGauntlet.Common/Build/ComponentBuilder.cs#L58-L94","documentation":"ComponentBuilder.CreateModifiedProjectClone requires the template .csproj path to be an absolute path so that Path.GetDirectoryName yields a non-null folder. When a null/relative path yields null from GetDirectoryName, it throws ArgumentException('Template csproj path should be absolute', nameof(templateCsProj)).","triggerScenarios":"CreateModifiedProjectClone (called by BuildLocalNuGetPackageAsync / BuildAppAsync) is passed a templateCsProj like 'Templates/My.csproj' or an empty string, so Path.GetDirectoryName returns null.","commonSituations":"Caller built the path from a relative working directory; passed a bare file name; passed a directory instead of a file path; misconfigured template location in test settings.","solutions":["Pass a fully rooted path: Path.GetFullPath(relativePath) or combine with the repo root before calling","Ensure the argument points to a .csproj file, not a directory","Log/assert the resolved path before calling CreateModifiedProjectClone during development","Fix the caller configuration so templateCsProj is populated with an absolute path"],"exampleFix":"// before\nawait builder.BuildLocalNuGetPackageAsync(\"Templates\\Lib.csproj\", ...);\n// after\nstring template = Path.GetFullPath(Path.Combine(repoRoot, \"Templates\", \"Lib.csproj\"));\nawait builder.BuildLocalNuGetPackageAsync(template, ...);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(templateCsProj) || !Path.IsPathRooted(templateCsProj))\n    throw new ArgumentException(\"templateCsProj must be an absolute file path\", nameof(templateCsProj));\nif (!File.Exists(templateCsProj)) throw new FileNotFoundException(templateCsProj);","typeGuard":"bool IsAbsoluteFilePath(string? p) => !string.IsNullOrWhiteSpace(p) && Path.IsPathRooted(p) && File.Exists(p);","tryCatchPattern":"try\n{\n    await builder.BuildLocalNuGetPackageAsync(templateCsProj, ...);\n}\ncatch (ArgumentException ex) when (ex.ParamName == nameof(templateCsProj))\n{\n    // resolve path with Path.GetFullPath and retry\n}","preventionTips":["Always construct template paths from a known repo root","Call Path.GetFullPath on any user/config-supplied path before use","Assert File.Exists on the csproj at startup","Never pass directories where a file path is expected"],"tags":["argument-validation","path","build","invalid-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}