This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: "TypeError: unhashable type" could often be more clear
Type: enhancement Stage: resolved
Components: Interpreter Core Versions:
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: drakebohan, iritkatriel, rhettinger, sfreilich
Priority: normal Keywords:

Created on 2020-06-25 12:48 by sfreilich, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (11)
msg372366 - (view) Author: Samuel Freilich (sfreilich) * Date: 2020-06-25 12:48
Currently, if you (for example) put a dict as a value in a set or key in a dict, you get:

TypeError: unhashable type: 'dict'

I'm pretty sure this wording goes back a long time, but I've noticed that Python beginners tend to find this really confusing. It fits into a pattern of error messages where you have to explain why the error message is worded the way it is after you explain why the error message occurs at all. There are many instances of:
https://stackoverflow.com/questions/13264511/typeerror-unhashable-type-dict

It would be clearer if the message was something like:

TypeError: 'dict' can not be used as a set value because it is an unhashable type.

(Or "dict key" instead of "set value".)

The exception is raised in PyObject_Hash, so that doesn't have some of the context about how/why hash was called. That's called in a lot of places.

Possibly, PyObject_Hash and PyObject_HashNotImplemented could take the format string passed to PyErr_Format as an optional second argument, defaulting to the current behavior? Then certain callers (in particular, the set and dict constructor, set and dict methods that add set values or add/modify dict keys) could provide clearer error messages.
msg377552 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2020-09-27 02:50
> It would be clearer if the message was something like:
> 
> TypeError: 'dict' can not be used as a set value because 
> it is an unhashable type.

IMO that doesn't help.  The trackback already shows the code where the exception occurred.  The user already knows the calling type, and the existing message tells them what type was passed in.  

Their real problem is that they still have to confront the notion of what "unhashable type" means and then need figure-out a way to fix it.  So the proposed extra information is just a distractor that doesn't get the user any closer to understanding or solving their problem.  

To get a user closer to the solution they would either need an explanation of what hashable means and/or be given a suggestion of how to fix it:

   TypeError: unhashable type: 'dict'.  Consider using an int,
   str, tuple, or frozenset.

That said, it is precarious to guess what the user intended, so it is difficult to suggest some form of "did you mean ..."
msg377559 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2020-09-27 10:49
Do you think it would help if the exception was of type UnhashableType (subclass of TypeError)? This would give the user a hint that this error is a thing which is worth looking for in the docs and understanding.
msg377576 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2020-09-27 18:00
> Do you think it would help if the exception was of type UnhashableType

That would not add more information. The message already says "unhashable type".  Saying it twice doesn't help.
msg377583 - (view) Author: Samuel Freilich (sfreilich) * Date: 2020-09-27 23:11
> The user already knows

The example I link to in the initial description appears to be one case where the user does not in fact know.

I do think context that this restriction applies to dict key in particular is very relevant. The line could use the same type for both the key and the value in a dict assignment, for example.

> TypeError: unhashable type: 'dict'.  Consider using an int, str, tuple, or frozenset.

That seems like a pretty reasonable wording, though I think mentioning "dictionary key" or "set item" specifically still helps.

It could also link to the documentation directly:
https://docs.python.org/3/glossary.html#term-hashable

Though other error messages don't generally follow that pattern.

> Saying it twice doesn't help.

As the comment you were responding to noted, putting it in the type implies there might be additional information in documentation (or at least provides a place in documentation to put that information). TypeError is too general to say something about that specifically:
https://docs.python.org/3/library/exceptions.html#TypeError
msg377585 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2020-09-28 04:22
> I've noticed that Python beginners tend to find this really confusing.

No minor tweak to the exception message will make this go away.  For understanding to occur, the only way to forward is to learn a bit about hashability.  That is a step that every beginner must take.

Fortunately, the term "hashable" is listed in the glossary.  Also the error message itself is easily Googled:

   https://docs.python.org/3/glossary.html#term-hashable

   https://www.google.com/search?q=TypeError%3A+unhashable+type%3A+%27dict%27&oq=TypeError%3A+unhashable+type%3A+%27dict%27

I suggest that you take this to the python-ideas list.  While there is a valid concern that a new user may not understand the error message (this is unfortunately true for many our error messages), the proposals don't actually improve the situation.

The first proposal adds hard-to-implement context information that still doesn't tell a user what the issue is.  The second proposal repeats information that is already being shown.  Neither proposal explains what is meant by unhashable type, why it matters, what would be an allowable hashable type, or how to fix the problem (which is what the user really wants to know).

After a discussion on python-ideas, if a better proposal is found, feel free to reopen this issue.
msg377599 - (view) Author: Samuel Freilich (sfreilich) * Date: 2020-09-28 12:52
> No minor tweak to the exception message will make this go away.  For understanding to occur, the only way to forward is to learn a bit about hashability.  That is a step that every beginner must take.

This is a derisive and beginner-hostile response that ignores half of what's been said by other participants in this thread.

> Also the error message itself is easily Googled

Yeah, the first thing that comes up is ~4k Stack Overflow entries where people are really confused by the error message.
msg377609 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2020-09-28 17:39
I think it's reasonable to discuss the problem on python-ideas rather than on a bugs issue, when it's not obvious what the right solution is.
msg377645 - (view) Author: Samuel Freilich (sfreilich) * Date: 2020-09-28 22:57
> I think it's reasonable to discuss the problem on python-ideas rather than on a bugs issue, when it's not obvious what the right solution is.

I did start a thread there. Don't object to that, if that's a better forum for this sort of thing.
msg378557 - (view) Author: Samuel Freilich (sfreilich) * Date: 2020-10-13 13:55
python-ideas thread: https://mail.python.org/archives/list/python-ideas@python.org/thread/B6OMGYIM47OVGOCZLEY3MEUJDFURJRDV/

The most minimal ideas from that seem to be:

1. Maybe link to the glossary from the error message (if links to documentation in error messages are permissible).

2. Add a glossary entry for "unhashable" for the sake of completeness (similar to how there are entries for both "immutable" and "mutable").
msg406385 - (view) Author: drakebohan (drakebohan) Date: 2021-11-16 04:54
The problem is that you can't use a list as the key in a dict, since dict keys need to be immutable.  This means that when you try to hash an unhashable object it will result an error. For ex. when you use a list as a key in the dictionary , this cannot be done because lists can't be hashed. The standard way to solve this issue is to cast a list to a tuple . TypeError: unhashable type: 'list' usually means that you are trying to use a list as an hash argument. The standard way to solve this issue is to cast a list to tuple.

Though tuples may seem similar to lists, they are often used in different situations and for different purposes. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can’t use lists as key.

http://net-informations.com/python/iq/unhashable.htm
History
Date User Action Args
2022-04-11 14:59:32adminsetgithub: 85286
2021-11-16 04:54:39drakebohansetnosy: + drakebohan
messages: + msg406385
2020-10-13 13:55:02sfreilichsetmessages: + msg378557
2020-09-28 22:57:37sfreilichsetmessages: + msg377645
2020-09-28 17:39:05iritkatrielsetmessages: + msg377609
2020-09-28 12:52:49sfreilichsetmessages: + msg377599
2020-09-28 04:22:45rhettingersetstatus: open -> closed
resolution: rejected
messages: + msg377585

stage: resolved
2020-09-27 23:11:49sfreilichsetmessages: + msg377583
2020-09-27 18:00:03rhettingersetmessages: + msg377576
2020-09-27 10:49:07iritkatrielsetnosy: + iritkatriel
messages: + msg377559
2020-09-27 02:50:59rhettingersetnosy: + rhettinger
messages: + msg377552
2020-09-27 00:01:21iritkatrielsettype: behavior -> enhancement
components: + Interpreter Core
2020-06-25 12:48:17sfreilichcreate