A System.Collections.Generic.Dictionary
is throwing KeyNotFoundException
, but I can't see which key is supposedly missing. How do I determine this?

- 98,240
- 88
- 296
- 433

- 65,625
- 67
- 195
- 317
-
The key of a dictionary can be any type. Using ToString() in the exception message will make the user's eyes bleed, adding way too much noise. Nor is there a requirement that ToString() is always overridden to display something useful. – Hans Passant Aug 29 '11 at 12:44
-
4@HansPassant: It still could have been a property on the exception class. – Daniel Hilgarth Dec 12 '11 at 09:28
-
1Depending on what you are trying to do, it might be a good idea to check the [`TryGetValue`](http://msdn.microsoft.com/en-us/library/bb347013.aspx) method on dictionaries. You can use it to create a safe dictionary lookup and save the overhead created by catching exceptions. – w5l Mar 04 '13 at 09:20
-
5@DanielHilgarth: In some situations, a dictionary key may contain confidential data, and code should assume that exception objects might get logged in such a way as to be visible to essentially anyone. While it may be handy for a class to offer a constructor parameter which would say that data passed to it should be considered non-confidential and may safely be exposed in exceptions, classes should not generally make such a presumption absent such a reason for doing so. – supercat Mar 04 '13 at 17:13
-
`if (!dictionary.TryGetValue(key, out value)) throw new KeyNotFoundException(key);` – Riegardt Steyn Nov 28 '14 at 09:17
-
You can always use the Debugger. – Петър Петров Feb 12 '18 at 18:39
8 Answers
Custom exception:
class WellknownKeyNotFoundException : KeyNotFoundException
{
public WellknownKeyNotFoundException(object key, string message)
: this(key, message, null) { }
public WellknownKeyNotFoundException(object key, string message, Exception innerException)
: base(message, innerException)
{
this.Key = key;
}
public object Key { get; private set; }
}
Handy extension method:
public TValue GetValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
{
try
{
return dic[key];
}
catch (KeyNotFoundException ex)
{
throw new WellknownKeyNotFoundException((object)key, ex.InnerException);
}
}
Usage:
var foo = new Foo();
var bar = new Bar();
IDictionary<Foo, Bar> dic = new Dictinary<Foo, Bar>
{
{ foo, bar }
};
try
{
dic.GetValue(foo);
}
catch (WellknownKeyNotFoundException ex)
{
var key = (Foo)ex.Key;
Assert.AreEqual(foo, key); // should be
}

- 8,142
- 6
- 42
- 71

- 98,240
- 88
- 296
- 433
-
-
2Instead of building your own extension method, use trygetvalue to get a more clean solution. – David Mårtensson Oct 15 '13 at 07:17
There is no way to tell this from the exception. You need to implement your own solution for this.

- 171,043
- 40
- 335
- 443
-
5Thanks for clarifying the situation. It's a bit weird though, that the exception can't communicate this? Any known rationale for this design? – aknuds1 Aug 29 '11 at 12:27
-
7@aknuds1: I don't know why it was designed like this. I certainly would have included the key. – Daniel Hilgarth Aug 29 '11 at 12:35
-
1@aknuds1 The key object would need a "readable" `ToString()` implementation for that to give any useful result. – Magnus Mar 04 '13 at 17:01
-
4@Magnus: Not really. The key could have been a property of type `object` on the exception. With this at least the code that handles the exception could analyze the key that was missing. But for the reason you mention, it should probably not be included in the exception message. – Daniel Hilgarth Sep 24 '13 at 16:03
-
1This is also true for example for new DateTime(a=50,b=50,c=50), it throws "Invalid date" but doesn't mention the parameters which are plain integers. It forced me to wrap the "new" call because the exception thrown is useless. It seems to be some kind of policy or (not) best practice in the .Net code. – Cesar Jul 23 '19 at 17:16
If it is possible for you to customize the implementation where the dictionary is declared, you can easily replace System.Collections.Generic.Dictionary by a custom type throwing a nicer KeyNotFoundException. While this is similar to the answer of abatishchev, I don't like the extension method he introduced, since it means that we have two different ways to achieve the exactly same thing. This should be avoided if possible. I solved the problem by using a "NiceDictionary" instead, which can be used exactly like the original Dictinary used as base class. The implementation is almost trivial:
/// <summary>
/// This is a nice variant of the KeyNotFoundException. The original version
/// is very mean, because it refuses to tell us which key was responsible
/// for raising the exception.
/// </summary>
public class NiceKeyNotFoundException<TKey> : KeyNotFoundException
{
public TKey Key { get; private set; }
public NiceKeyNotFoundException(TKey key, string message)
: base(message, null)
{
this.Key = key;
}
public NiceKeyNotFoundException(TKey key, string message, Exception innerException)
: base(message, innerException)
{
this.Key = key;
}
}
/// <summary>
/// This is a very nice dictionary, because it throws a NiceKeyNotFoundException that
/// tells us the key that was not found. Thank you, nice dictionary!
/// </summary>
public class NiceDictionary<TKey, TVal> : Dictionary<TKey, TVal>
{
public new TVal this[TKey key]
{
get
{
try
{
return base[key];
}
catch (KeyNotFoundException knfe)
{
throw new NiceKeyNotFoundException<TKey>(key, knfe.Message, knfe.InnerException);
}
}
set
{
try
{
base[key] = value;
}
catch (KeyNotFoundException knfe)
{
throw new NiceKeyNotFoundException<TKey>(key, knfe.Message, knfe.InnerException);
}
}
}
}
As said, you can use it exaclty as you would use the original Dictionary. It magically works because of the overridden array operator ([]).

- 189
- 1
- 9
-
1Looks like try/catch is redundant in setter because new entry should be created in case of the new key – sarh Apr 16 '13 at 09:27
-
Also, in getter instead of try/catch/throw it is better to do TryGetValue, and if key not found then throw an exception. It should be better from performance point of view – sarh Apr 16 '13 at 09:37
-
2It should be mentioned that any code that accesses a `NiceDictionary` through an interface will find the original indexer and not get a `NiceKeyNotFoundException`. This could be fixed by reimplementing all the interfaces, but at the cost of exploding the code. – Ben Voigt Jan 14 '21 at 23:35
You can't just by looking at the exception. You will have to break into the debugger when the exception is thrown (Debug -> Exceptions... in Visual Studio) and see what key has been accessed. Alternatively you could catch the exception in code and print it out (e.g. to the console).

- 48,890
- 37
- 186
- 278
-
Well, this was my strategy, but it can't pinpoint the reason exactly since there are several dictionary accesses in one statement... I solved it by breaking the statement into several smaller ones, but it's kinda clunky. – aknuds1 Aug 29 '11 at 12:26
use the debuger (if needed check the ThrowOnCatch in Debug->Exceptions) and have a look

- 51,810
- 9
- 92
- 119
I used this extension method
internal static class KeyNotFoundExceptionExtensions
{
public static string GetKeyValue(this KeyNotFoundException ex)
{
var match = Regex.Match(ex.Message, @"'(.*?)'");
if (match.Success)
return match.Groups[1].Value;
throw ex;
}
}

- 521
- 4
- 14
-
This works only on recent versions of .Net (at least older than .Net Framework 4.8). Seeing `throw ex` hurts my soul, though. – Arkane Mar 29 '23 at 10:40
-
you would think that they could add the attempted key to the exception.data
this is what i did
public static void SetGlobals()
{
string currentKey = "None";
try
{
currentKey = "CurrentEnvironment";
Globals.current_environment = Settings[currentKey];
currentKey = "apiUrl";
Globals.api_url = Settings[currentKey];
currentKey = "whatever";
Globals.whatever= Settings[currentKey];
if (AppDomain.CurrentDomain.GetData(".devEnvironment") as bool? == true)
Globals.api_url = "http://localhost:59164/api";
}
catch(KeyNotFoundException)
{
DBClass.logEvent("Error", "AppSettings", "Missing Setting: " + currentKey);
}
}

- 336
- 4
- 10
System.Collections.Generic.KeyNotFoundException has been thrown
If you are using DotNet Core with Xamarin Studio and you get this error you can check if the key exists with the following condition:
if (Application.Current.Properties.ContainsKey("userCredentials")) {
//now process...
}

- 188
- 3