Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure Table Storage Exception: 409 Conflict unexpected?

I'm using WindowsAzure.Storage nuget package version 9.0.0.

Install-Package WindowsAzure.Storage -Version 9.0.0

The following code (table.CreateIfNotExistsAsync()) throws the error: The remote server returned an error: (409) Conflict.

CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference(tableName);
try
{
    if (await table.CreateIfNotExistsAsync())
    {
        log.Info(string.Format("Created Table named: {0}", tableName));
    }
}
catch (StorageException)
{
    log.Error("If you are running with the default configuration please make sure you have started the storage emulator. Press the Windows key and type Azure Storage to select and run it from the list of applications - then restart the sample.");
    throw;
}

return table;

If I check the StorageException details, I find this message: The table specified already exists.

Stack Trace:

   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndExecuteAsync[T](IAsyncResult result) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Core\Executor\Executor.cs:line 57

enter image description here

This code works fine:

CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference(tableName);

try
{
    //if (await table.CreateIfNotExistsAsync())
    //{
    //    log.Info(string.Format("Created Table named: {0}", tableName));
    //}

    if (!table.Exists())
    {
        await table.CreateAsync();

        log.Info(string.Format("Created Table named: {0}", tableName));
    }
}
catch (StorageException)
{
    log.Error("If you are running with the default configuration please make sure you have started the storage emulator. Press the Windows key and type Azure Storage to select and run it from the list of applications - then restart the sample.");
    throw;
}

return table;

I know I have tables that already exists and they are NOT currently being deleted. Why am I getting this error? Since the table does exist, I would expect this to perform and existence check and just return true, not throw a storage exception.

Edit: This is how I'm creating the CloudStorageAccount

public static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString)
{
    CloudStorageAccount storageAccount;
    try
    {
        storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    }
    catch (FormatException fe)
    {
        log.Error("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the application.", fe);
        throw;
    }
    catch (ArgumentException ae)
    {
        log.Error("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample.", ae);
        throw;
    }

    return storageAccount;
}

Storage connection string looks like this:

<add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=something;AccountKey=somekeygoeshere==" />
like image 982
Jason Eades Avatar asked Feb 20 '18 20:02

Jason Eades


3 Answers

CreateIfNotExists is throwing the exception.
There was a change in implementation of the method CloudBlobContainer.CreateIfNotExists or CloudTable.CreateIfNotExists.

The implementation in the 7.1.2 storage client library is the following:

  1. Make a call to check to see if the storage container or table exists (HTTP HEAD request).

  2. If it exists do nothing.

  3. If it doesn’t exist then make a call to create the container or table.
     

In the storage client library 8.1.1 the implementation is the following:
 

  1. Make a call to create the container or table (HTTP PUT Request).

  2. If an error was returned (HTTP 409) because the container or table already exists then do nothing. The error is handled.

  3. If the container or table did not exist then create would have succeeded.

I checked with 9.0 and that behavior still exists

like image 123
Shane Raboin Avatar answered Oct 27 '22 08:10

Shane Raboin


A nice workaround could be:

if (!container.Exists())
        {
            container.CreateIfNotExists();
        }
like image 9
Kamran Avatar answered Oct 27 '22 06:10

Kamran


How did you create CloudStorageAccount object? I think it was probably created via SAS which doesn't have List Tables permission, so table.Exists() always returns false per storage REST API design in order not to leak such information to unauthorized users. The reason why table.CreateIfNotExistsAsync() didn't meet this issue is that the method directly calls Create Table REST API without a prior List Tables checking, and 409 Conflict exception is swallowed inside table.CreateIfNotExistsAsync() method on purpose (in order to implement "create if not exists" functionality, since 409 Conflict exception means the table already exists so the method can just ignore the error and do nothing).

If my theory above applies to your case, please use a SAS with List Tables permission instead of the existing SAS, or use shared account key directly to create CloudStorageAccount object.

like image 1
Zhaoxing Lu Avatar answered Oct 27 '22 08:10

Zhaoxing Lu