When working with Dataverse plug-ins, you may encounter the “The given key wasn’t present in the dictionary” error. This issue occurs when your plug-in code attempts to access a key that does not exist in the ParameterCollection or Entity.Attributes dictionary.
In this blog, we’ll explore the causes of this error, how to debug it, and best practices to avoid running into it in your Dataverse plug-ins.
🚨 Understanding the Error
Error Message:
Error Code: -2147220891
Error Message: ISV code aborted the operation.
or
Error Code: -2147220956
Error Message: An unexpected error occurred from ISV code.
These error messages indicate that the plug-in attempted to access a key that was not present in a dictionary (such as InputParameters or Entity.Attributes).
🔍 Why Does This Happen?
The error commonly occurs due to:
1️⃣ Accessing Missing Keys in InputParameters
- The plug-in expects a key (e.g.,
Target) inInputParameters, but it is missing.
2️⃣ Accessing Attributes That Were Not Passed in an Update
- In an
Updateoperation, only modified fields are included inEntity.Attributes. Attempting to access a missing attribute causes the error.
3️⃣ Case Sensitivity in Attribute Names
- Keys in
Entity.Attributesare case-sensitive. If you mistype an attribute name, it won’t be found.
4️⃣ Attempting to Access Related Entities Without Checking Existence
- The plug-in assumes a related entity exists in the
PreImageorPostImage, but it is missing.
🔧 How to Fix This Error
1️⃣ Validate That Keys Exist Before Accessing Them
Instead of directly accessing attributes, use the .Contains() method to check for existence.
✅ Correct Approach:
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.Contains("name"))
{
string name = entity["name"].ToString();
}
}
❌ Incorrect Approach (Leads to the Error):
string name = (string)context.InputParameters["Target"]["name"]; // Throws error if "name" is missing
2️⃣ Use GetAttributeValue<T>() to Safely Retrieve Values
Instead of entity["attributeName"], use GetAttributeValue<T>().
✅ Safe Approach:
string name = entity.GetAttributeValue<string>("name");
If the attribute is missing, this method returns null instead of throwing an error.
3️⃣ Verify Pre-Images and Post-Images Before Using Them
If your plug-in relies on pre-image or post-image snapshots, ensure they exist before accessing them.
✅ Safe Approach:
if (context.PreEntityImages.Contains("PreImage"))
{
Entity preImage = context.PreEntityImages["PreImage"];
if (preImage.Contains("emailaddress1"))
{
string email = preImage["emailaddress1"].ToString();
}
}
4️⃣ Debugging the Issue
If you’re unsure which key is missing, add tracing to log available keys.
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
foreach (var key in entity.Attributes.Keys)
{
tracingService.Trace($"Available Key: {key}");
}
}
This helps identify which keys are present in the dictionary at runtime.
📌 Best Practices to Avoid This Error
✔ Always check if a key exists before accessing it (Contains() method).
✔ Use GetAttributeValue<T>() instead of directly accessing dictionary keys.
✔ Ensure pre-images and post-images exist before accessing them.
✔ Use tracing to debug available keys.
📢 Coming Up Next…
In Blog 9, we’ll explore “Error: You Can’t Start a Transaction with a Different Isolation Level Than is Already Set on the Current Transaction”, discussing why nested transactions in plug-ins can cause failures and how to handle database operations properly.
Stay tuned for another troubleshooting deep dive! 🚀
