Skip to content

Fix ItemWithPath throwing on null/empty/whitespace path instead of generating malformed URLs#3072

Open
Copilot wants to merge 6 commits into
mainfrom
copilot/fix-sdk-url-construction-bug
Open

Fix ItemWithPath throwing on null/empty/whitespace path instead of generating malformed URLs#3072
Copilot wants to merge 6 commits into
mainfrom
copilot/fix-sdk-url-construction-bug

Conversation

Copy link
Copy Markdown

Copilot AI commented Mar 9, 2026

  • Explore current state of source and test files
  • Extract duplicated validation logic into NormalizePathOrThrow private helper
  • Fix missing StringComparison.Ordinal in second overload's StartsWith
  • Update tests to also assert ParamName == "path" on thrown exceptions
  • Run tests to validate changes (22/22 passed)
  • Run parallel validation
Original prompt

This section details on the original issue you should resolve

<issue_title>SDK URL Construction Bug with Empty Filenames</issue_title>
<issue_description>During testing of empty filename scenarios, we discovered a bug in the Microsoft Graph .NET SDK's URL construction when using [ItemWithPath("")]with empty strings.

When calling [graphClient.Drives[driveId].Root.ItemWithPath("").Content.GetAsync()] the SDK generates malformed URLs that duplicate path segments:

GET https://graph.microsoft.com/v1.0/drives/{driveId}/root:443/v1.0/drives/{driveId}/root:/content HTTP/2.0

This issue stems from the [ItemWithPath] extension method in DriveItemRequestBuilderExtensions.cs
builder.Path += $":{path}:"; // When path is "", this becomes "::"

Exected behavior:
https://graph.microsoft.com/v1.0/drives/{driveId}/root::/content
and the SDK should probably return an exception for null filenames

How to repro:

Create a GraphServiceClient instance
Call [graphClient.Drives[driveId].Root.ItemWithPath("").Content.GetAsync()])
Observe the generated HTTP request URL in network logs

SDK version: 5.94.0

Debug output:

HTTP REQUEST >>>>>>>>
------ JWT payload (relevant ID claims only) ------
"app_displayname": DAMS vNext SPE
"appid": 2b376c51-fcaf-4c86-823a-622ecc45c27e
"aud": https://graph.microsoft.com/
"idtyp": app
"iss": https://sts.windows.net/0f7c36b4-4e13-46ce-a1ea-7e6ecb8dd391/
"oid": 81c7703e-f477-4459-a491-235266b06df1
"sub": 81c7703e-f477-4459-a491-235266b06df1
"tid": 0f7c36b4-4e13-46ce-a1ea-7e6ecb8dd391
------ JWT payload (relevant ID claims only) ------

GET https://graph.microsoft.com/v1.0/drives/{driveId}/root:443/v1.0/drives/{driveId}/root:/content HTTP/2.0
Accept: application/octet-stream, application/json
Authorization: REDACTED
Cache-Control: no-store, no-cache
client-request-id: 6e8f0db8-bade-4886-b22f-e98b7f2bc06f
FeatureFlag: 00000003
SdkVersion: graph-dotnet-core/3.2.4 (featureUsage=00000003; hostOS=Microsoft Windows NT 10.0.22631.0; hostArch=X64; runtimeEnvironment=.NET 10.0.0-rc.2.25502.107;)
User-Agent: kiota-dotnet/1.17.1

[no content]

[2025-10-24T21:43:14.2060635+00:00]: Sending request... completed in 53ms [2025-10-24T21:43:14.2599208+00:00].

<<<<<<<< HTTP RESPONSE <<<<<<<<
HTTP/2.0 400 Bad Request
client-request-id: 6e8f0db8-bade-4886-b22f-e98b7f2bc06f
Content-Type: application/json
Date: Fri, 24 Oct 2025 21:43:13 GMT
request-id: c83d5fd8-1a6f-4a1c-b330-8e720631c89b
Strict-Transport-Security: max-age=31536000
x-ms-ags-diagnostic: {"ServerInfo":{"DataCenter":"East US","Slice":"E","Ring":"5","ScaleUnit":"000","RoleInstance":"BL6PEPF0002814A"}}

{
"error": {
"code": "BadRequest",
"message": "Resource not found for the segment \u0027root:443\u0027.",
"innerError": {
"date": "2025-10-24T21:43:14",
"request-id": "c83d5fd8-1a6f-4a1c-b330-8e720631c89b",
"client-request-id": "6e8f0db8-bade-4886-b22f-e98b7f2bc06f"
}
}
}</issue_description>

Comments on the Issue (you are @copilot in this section)

@lramosvea The extension method should return an argument null exception is the string provided is null and argument exception when the string provided is empty or white space.

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Microsoft Reviewers: Open in CodeFlow

Co-authored-by: lramosvea <77297467+lramosvea@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix SDK URL construction bug with empty filenames Fix ItemWithPath throwing on null/empty/whitespace path instead of generating malformed URLs Mar 9, 2026
gavinbarron
gavinbarron previously approved these changes May 19, 2026
@gavinbarron gavinbarron marked this pull request as ready for review May 19, 2026 16:23
@gavinbarron gavinbarron requested a review from a team as a code owner May 19, 2026 16:23
Copilot AI review requested due to automatic review settings May 19, 2026 16:23
@gavinbarron gavinbarron enabled auto-merge (squash) May 19, 2026 16:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR makes ItemWithPath fail fast for invalid path inputs to prevent malformed Microsoft Graph URLs when null, empty, or whitespace strings are provided.

Changes:

  • Added argument validation to both ItemWithPath overloads (RootRequestBuilder and DriveItemItemRequestBuilder).
  • Added unit tests covering null, empty, and whitespace path inputs for both overloads.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
tests/Microsoft.Graph.DotnetCore.Test/Requests/Extensions/DriveItemRequestBuilderExtensionsTests.cs Adds test coverage for invalid path inputs on both ItemWithPath overloads.
src/Microsoft.Graph/Extensions/DriveItemRequestBuilderExtensions.cs Adds null + empty/whitespace validation and normalizes missing leading / for path.

Comment on lines 45 to 55
public static CustomDriveItemItemRequestBuilder ItemWithPath(this Microsoft.Graph.Drives.Item.Root.RootRequestBuilder rootRequestBuilder, string path)
{
if (!string.IsNullOrEmpty(path))
if (path is null)
throw new ArgumentNullException(nameof(path));
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException("path cannot be empty or whitespace.", nameof(path));

if (!path.StartsWith("/"))
{
if (!path.StartsWith("/"))
{
path = string.Format("/{0}", path);
}
path = string.Format("/{0}", path);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in commit 23f4c9e. The duplicated validation and leading-slash normalization logic has been extracted into a private NormalizePathOrThrow(string path) helper used by both overloads. This also consolidates the StringComparison.Ordinal fix. Tests now assert ParamName == "path" on all thrown exceptions.

Comment thread src/Microsoft.Graph/Extensions/DriveItemRequestBuilderExtensions.cs Outdated
public void ItemByPath_ThrowsArgumentNullException_WhenPathIsNull_Root()
{
var graphServiceClient = new GraphServiceClient(new MockAuthenticationProvider().Object);
Assert.Throws<ArgumentNullException>(() => graphServiceClient.Drives["driveId"].Root.ItemWithPath(null));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in commit 23f4c9e. The test now captures the exception and asserts ex.ParamName == "path".

public void ItemByPath_ThrowsArgumentException_WhenPathIsEmptyOrWhitespace_Root(string path)
{
var graphServiceClient = new GraphServiceClient(new MockAuthenticationProvider().Object);
Assert.Throws<ArgumentException>(() => graphServiceClient.Drives["driveId"].Root.ItemWithPath(path));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in commit 23f4c9e. The test now captures the exception and asserts ex.ParamName == "path".

public void ItemByPath_ThrowsArgumentNullException_WhenPathIsNull_DriveItem()
{
var graphServiceClient = new GraphServiceClient(new MockAuthenticationProvider().Object);
Assert.Throws<ArgumentNullException>(() => graphServiceClient.Drives["driveId"].Items["itemId"].ItemWithPath(null));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in commit 23f4c9e. The test now captures the exception and asserts ex.ParamName == "path".

public void ItemByPath_ThrowsArgumentException_WhenPathIsEmptyOrWhitespace_DriveItem(string path)
{
var graphServiceClient = new GraphServiceClient(new MockAuthenticationProvider().Object);
Assert.Throws<ArgumentException>(() => graphServiceClient.Drives["driveId"].Items["itemId"].ItemWithPath(path));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in commit 23f4c9e. The test now captures the exception and asserts ex.ParamName == "path".

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
auto-merge was automatically disabled May 19, 2026 16:56

Head branch was pushed to by a user without write access

Copilot AI requested a review from gavinbarron May 19, 2026 16:57
@gavinbarron gavinbarron enabled auto-merge (squash) May 19, 2026 17:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SDK URL Construction Bug with Empty Filenames

6 participants