Sitecore General error when submitting contact – Another contact with the same identifier already exists

In Sitecore when creating your own contacts you can get the following exception:

10604 10:16:27 ERROR General error when submitting contact.
Exception: System.InvalidOperationException
Message: Another contact with the same identifier already exists.
Source: Sitecore.Analytics.MongoDB
   at Sitecore.Analytics.Data.DataAccess.MongoDb.MongoDbDataAdapterProvider.SaveContactWithIdentifier(IContact contact, ContactSaveOptions saveOptions)
   at Sitecore.Analytics.Data.DataAccess.MongoDb.MongoDbDataAdapterProvider.<>c__DisplayClass9.<SaveContact>b__7()
   at Sitecore.Analytics.Data.DataAccess.MongoDb.MongoDbDataAdapterProvider.Try(Action action)
   at Sitecore.Analytics.Data.DataAccess.MongoDb.MongoDbDataAdapterProvider.SaveContact(IContact contact, ContactSaveOptions saveOptions)
   at Sitecore.Analytics.Data.ContactRepository.SaveContact(Contact contact, ContactSaveOptions options)
   at Sitecore.Analytics.Tracking.ContactManager.SubmitContact(Contact contact, ContactSaveOptions options, Contact& realContact)

The error can occur if you try to flush a contact with a new contact ID but with an existing identifier. It usually is a result of Sitecore having a mismatch between what the ContactRepository and the MongoDB contains.

This pseudocode explains the situation:

ContactRepository contactRepository = Factory.CreateObject("tracking/contactRepository", true) as ContactRepository;
ContactManager contactManager = Factory.CreateObject("tracking/contactManager", true) as ContactManager;
// Contact is loaded from repository but repository cannot find it
Contact contact = contactRepository.LoadContactReadOnly(username);
// ... so we try to create it
if (contact == null)
{
  // Contact is created in memory
  contact = contactRepository.CreateContact(ID.NewID);
 contact.Identifiers.Identifier = username;
  // And we try to write it to xDB (MongoDB)
  // but the contact is already there. 
  contactManager.FlushContactToXdb(contact);
}

The problem arises as the FlushContactToXdb does not throw an exception, so you are left with the impression that the Contact is created and everything is fine.

If you are using the ExtendedContactRepository as I described in the blog post Sitecore Contacts – Create and save contacts to and from xDB (MongoDB), you risk that the GetOrCreateContact method goes in an infinite loop because:

  1. We try to load the contact, but the contact is not found
  2. We Create a new contact
  3. We flush the contact, but the flush method fails silently
  4. We call step 1

To avoid the infinite loop, please see Dan’s suggestion to how to solve it:

https://briancaos.wordpress.com/2015/10/09/sitecore-contacts-create-and-save-contacts-directly-to-and-from-xdb-mongodb/#comment-5890

Or you can add a retry counter in the class.

Add the following 2 lines to the class:

private const int _MAX_RETRIES = 10;
private int _retries;

Then modify the private method GetOrCreateContact:

private Contact GetOrCreateContact(string username, LockAttemptResult<Contact> lockAttempt, ContactRepository contactRepository, ContactManager contactManager)
{
  switch (lockAttempt.Status)
  {
	case LockAttemptStatus.Success:
	  Contact lockedContact = lockAttempt.Object;
	  lockedContact.ContactSaveMode = ContactSaveMode.AlwaysSave;
	  return lockedContact;

	case LockAttemptStatus.NotFound:
	  Contact createdContact = CreateContact(username, contactRepository);
	  Log.Info(string.Format("{0}: Flushing contact '{1}' (contact ID '{2}') to xDB.", GetType().Name, createdContact.Identifiers.Identifier, createdContact.ContactId), this);
	  contactManager.FlushContactToXdb(createdContact);

	  // NEW CODE: Check for retries, and throw an exception if retry count is reached
	  _retries++;
	  if (_retries >= _MAX_RETRIES)
		throw new Exception(string.Format("ExtendedContactRepository: Contact {0} could not be created. ", username));
	  // END NEW CODE

	  return GetOrCreateContact(username);

	default:
	  throw new Exception("ExtendedContactRepository: Contact could not be locked - " + username);
  }
}

This is still experimental code, but as described before, so is the ExtendedContactRepository.

MORE TO READ:

 

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in .net, c#, General .NET, Sitecore 8 and tagged , , , , , . Bookmark the permalink.

2 Responses to Sitecore General error when submitting contact – Another contact with the same identifier already exists

  1. Pingback: Sitecore Contacts – Create and save contacts to and from xDB (MongoDB) | Brian Pedersen's Sitecore and .NET Blog

  2. Pingback: Sitecore contact cannot be loaded, code never responds | Brian Pedersen's Sitecore and .NET Blog

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.