{"record":{"id":"dfd107929848d43f","repo":"dotnet/reactive","slug":"template-csproj-path-should-refer-to-a-file-not-a-directory","errorCode":null,"errorMessage":"Template csproj path should refer to a file, not a directory","messagePattern":"Template csproj path should refer to a file, not a directory","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Test/Gauntlet/RxGauntlet.Common/Build/ComponentBuilder.cs","lineNumber":78,"sourceCode":"                ..(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        }\n\n        _projectClones.Clear();","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Test/Gauntlet/RxGauntlet.Common/Build/ComponentBuilder.cs#L60-L96","documentation":"Immediately after deriving the folder, CreateModifiedProjectClone calls Path.GetFileName(templateCsProj); if that returns null (or the path referred to a directory), it throws ArgumentException('Template csproj path should refer to a file, not a directory'). The clone step needs the file name to copy the project into the temporary clone folder.","triggerScenarios":"templateCsProj ends with a directory separator or names a directory (e.g., 'C:\\repo\\Templates\\' or a trailing slash), so Path.GetFileName cannot yield a file name.","commonSituations":"Caller concatenated the path with a trailing separator; passed a directory path where a file path was expected; template path built by string joining ending in '/' or '\\\\'.","solutions":["Trim trailing directory separators and append the .csproj file name before calling","Validate File.Exists(templateCsProj) at the call site to catch wrong paths early","Pass the actual project file, not the folder containing it","Fix the caller's path-composition code so it always ends with a file name"],"exampleFix":"// before\nstring template = Path.Combine(root, \"Templates\", \"Lib\"); // directory\n// after\nstring template = Path.Combine(root, \"Templates\", \"Lib\", \"Lib.csproj\");","handlingStrategy":"validation","validationCode":"templateCsProj = templateCsProj.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);\nif (Directory.Exists(templateCsProj) || !templateCsProj.EndsWith(\".csproj\"))\n    throw new ArgumentException(\"Expected a .csproj file path\", nameof(templateCsProj));","typeGuard":"bool IsCsprojFile(string? p) => !string.IsNullOrWhiteSpace(p) && p.EndsWith(\".csproj\") && File.Exists(p);","tryCatchPattern":"try\n{\n    await builder.BuildAppAsync(templateCsProj, ...);\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"refer to a file\"))\n{\n    // append the project file name and retry\n}","preventionTips":["Trim trailing separators when building paths by string concatenation","End every template path with the actual .csproj file name","Validate with File.Exists before invoking the builder","Prefer Path.Combine over manual string joining to avoid separator bugs"],"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"}