Azure / azure-sdk-for-net

This repository is for active development of the Azure SDK for .NET. For consumers of the SDK we recommend visiting our public developer docs at https://learn.microsoft.com/dotnet/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-net.
MIT License
5.35k stars 4.65k forks source link

[BUG] DataLakeFileClient.UploadAsync Metadata cannot be an empty dictionary. Has to be null instead. #41903

Open rafal-zieba opened 7 months ago

rafal-zieba commented 7 months ago

Library name and version

Azure.Storage.Files.DataLake 12.17.1

Describe the bug

This fails with System.ArgumentOutOfRangeException: StartIndex cannot be less than zero. (Parameter 'startIndex'):

var dataLakeFileUploadOptions = new DataLakeFileUploadOptions
{
    Metadata = new Dictionary<string, string>(),
};

await dataLakeFileClient.UploadAsync(stream, dataLakeFileUploadOptions, cancellationToken);

but this works fine:

var dataLakeFileUploadOptions = new DataLakeFileUploadOptions
{
    Metadata = null,
};

await dataLakeFileClient.UploadAsync(stream, dataLakeFileUploadOptions, cancellationToken);

and the reason is here (the -1 part when the StringBuilder is still empty): https://github.com/Azure/azure-sdk-for-net/blob/675cf1fc091d02e385f4f8455beab2e9a40adc58/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakePathClient.cs#L750C13-L750C41

Expected behavior

Works with metadata set to an empty dictionary

Actual behavior

System.ArgumentOutOfRangeException: StartIndex cannot be less than zero. (Parameter 'startIndex')
    at System.Text.StringBuilder.Remove(Int32 startIndex, Int32 length)
    at Azure.Storage.Files.DataLake.DataLakePathClient.BuildMetadataString(IDictionary`2 metadata)
    at Azure.Storage.Files.DataLake.DataLakePathClient.CreateInternal(PathResourceType resourceType, PathHttpHeaders httpHeaders, IDictionary`2 metadata, String permissions, String umask, String owner, String group, IList`1 accessControlList, String leaseId, Nullable`1 leaseDuration, Nullable`1 timeToExpire, Nullable`1 expiresOn, String encryptionContext, DataLakeRequestConditions conditions, Boolean async, CancellationToken cancellationToken)
    at Azure.Storage.Files.DataLake.DataLakeFileClient.<>c__DisplayClass106_0.<<GetPartitionedUploaderBehaviors>b__0>d.MoveNext()
         --- End of stack trace from previous location ---
    at Azure.Storage.PartitionedUploader`2.UploadInternal(Stream content, Nullable`1 expectedContentLength, TServiceSpecificData args, IProgress`1 progressHandler, Boolean async, CancellationToken cancellationToken)
    at Azure.Storage.Files.DataLake.DataLakeFileClient.StagedUploadInternal(Stream content, DataLakeFileUploadOptions options, Boolean async, CancellationToken cancellationToken)

Reproduction Steps

var dataLakeFileUploadOptions = new DataLakeFileUploadOptions
{
    Metadata = new Dictionary<string, string>(),
};

await dataLakeFileClient.UploadAsync(stream, dataLakeFileUploadOptions, cancellationToken);

Environment

No response

github-actions[bot] commented 7 months ago

Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @sumantmehtams.