KeyNotFoundException: The given key was not present in the dictionary

Problem

The following exception is thrown when you try to get a value from a dictionary using a key that doesn’t exist in the dictionary:

KeyNotFoundException: ‘The given key was not present in the dictionary.’

Consider the following the example of initializing a dictionary with a few key/value pairs, and then trying to access non-existent keys:

static void Main(string[] args)
{
	Dictionary<string, string> storeManagerMap = new Dictionary<string, string>()
	{
		{ "Detroit", "Alice" },
		{ "Chicago", "Bob" }
	};

	string cityQuery = "";
	while (cityQuery != "quit")
	{
		Console.Write("I want the manager for city: ");
		cityQuery = Console.ReadLine();
		Console.WriteLine($"The manager for {cityQuery} is {storeManagerMap[cityQuery]}");
	}
	Console.ReadKey();
}
Code language: C# (cs)

When the user enters a city name that isn’t in the dictionary, such as “New York”, it’ll throw KeyNotFoundException.

Solution

The solution depends on one question: do you expect the key to always be in the dictionary?

Scenario 1 – The key might not exist

In this scenario, the user is supplying the key. In my example, they are supplying a city name and want to know the manager in that city.

Because the input is coming from the user, it’s possible the key might not exist in the dictionary. We can guard against that and report a meaningful error to the user instead of throwing an exception.

string manager;
if(storeManagerMap.TryGetValue(cityQuery, out manager))
{
	Console.WriteLine($"The manager for {cityQuery} is {manager}");
}
else
{
	Console.WriteLine($"There is no store in {cityQuery}");
}
Code language: C# (cs)

This is an example of the Try Pattern. Take a look at this interesting article on the subject.

Scenario 2 – The key must always exist

If the key must always exist in the dictionary, this means our code is attempting to access the dictionary with a known key, and KeyNotFoundException is truly unexpected. It may be appropriate to throw an exception here. But since you’re reading this article, I’m assuming you don’t want it to throw KeyNotFoundException, and you would rather deal with default values. If so, please continue forward.

This problem tends to happen if you are initially populating the dictionary from a database query (or some other external data source), and instead of a row with a null / missing value, it simply does not have the row.

Because the code is probably accessing the dictionary from several different places, you may not want to try to solve this with the TryGetValue() approach. An alternative approach is to initialize the dictionary with default values for known keys.

For example, let’s say I’m populating my dictionary in the code using the following SQL query:

SELECT c.CityName, m.Manager
FROM [City] c
INNER JOIN [Manager] m
ON m.CityName = c.CityName
Code language: SQL (Structured Query Language) (sql)

In my City table I have Detroit, Chicago, and New York. There is no manager for New York. Because this query is using an INNER JOIN, it doesn’t even return a row for New York.

CityName	Manager
Detroit   	Alice     
Chicago   	Bob       Code language: plaintext (plaintext)

Hence, when I go to access the dictionary with the key “New York,” I’ll get KeyNotFoundException.

In order to get the default value for New York, I would need to change the query to use a LEFT JOIN instead:

SELECT c.CityName, m.Manager
FROM [City] c
LEFT JOIN [Manager] m
ON m.CityName = c.CityName
Code language: SQL (Structured Query Language) (sql)

This would return one row for every city, therefore I would have a row for “New York.”

CityName	Manager
Detroit   	Alice     
Chicago   	Bob       
New York  	NULLCode language: plaintext (plaintext)

Now when I’m populating the dictionary, I would see that the “New York” row has no manager, and I could default the value to whatever is appropriate. The appropriate value will depend on your specific situation. You may want to keep it null, or use the Null Object Pattern.

The key takeaway here is that if your code is attempting to use keys that must exist, then the best solution is to initialize the dictionary with all of the known keys and use default values when there is no valid value available.

Comments are closed.