diff --git a/dask/core.py b/dask/core.py
--- a/dask/core.py
+++ b/dask/core.py
@@ -218,9 +218,26 @@ def iskey(key: object) -> bool:
 
 
 def validate_key(key: object) -> None:
-    """Validate the format of a dask key."""
-    if not iskey(key):
-        raise TypeError(f"Unexpected key type {type(key)} (value: {key!r})")
+    """Validate the format of a dask key.
+
+    See Also
+    --------
+    iskey
+    """
+    if iskey(key):
+        return
+    typ = type(key)
+
+    if typ is tuple:
+        index = None
+        try:
+            for index, part in enumerate(cast(tuple, key)):  # noqa: B007
+                validate_key(part)
+        except TypeError as e:
+            raise TypeError(
+                f"Composite key contains unexpected key type at {index=} ({key=!r})"
+            ) from e
+    raise TypeError(f"Unexpected key type {typ} ({key=!r})")
 
 
 @overload

diff --git a/dask/tests/test_core.py b/dask/tests/test_core.py
--- a/dask/tests/test_core.py
+++ b/dask/tests/test_core.py
@@ -73,9 +73,12 @@ def test_iskey_numpy_types():
 def test_validate_key():
     validate_key(1)
     validate_key(("x", 1))
-    with pytest.raises(TypeError):
+    with pytest.raises(TypeError, match="Unexpected key type.*list"):
         validate_key(["x", 1])
 
+    with pytest.raises(TypeError, match="unexpected key type at index=1"):
+        validate_key((2, int))
+
 
 def test_istask():
     assert istask((inc, 1))

Exception from `validate_key` is misleading for composite keys
When validating a key tuple with an invalid component, the exception is currently not helpful for identifying the problem and might even be misleading:

```python
import numpy as np
from dask.core import validate_key
validate_key((1, np.int64(2), 3))
```
creates the following traceback:

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/hendrikmakait/projects/dask/dask/dask/core.py", line 223, in validate_key
    raise TypeError(f"Unexpected key type {type(key)} (value: {key!r})")
TypeError: Unexpected key type <class 'tuple'> (value: (1, 2, 3))
```

That is, the exception suggests that `tuple` is an invalid type a key even though it is the _only_ valid type for creating composite keys. The printed key also doesn't give any hint that the `2` is to blame here.

dask/tests/test_core.py::test_validate_key
dask/tests/test_core.py::test_getcycle dask/tests/test_core.py::TestGet::test_get dask/tests/test_core.py::test_istask dask/tests/test_core.py::test_get_dependencies_empty dask/tests/test_core.py::TestGet::test_nested_badkey dask/tests/test_core.py::TestGet::test_data_not_in_dict_is_ok dask/tests/test_core.py::TestGet::test_with_HighLevelGraph dask/tests/test_core.py::test_subs_with_unfriendly_eq dask/tests/test_core.py::TestGet::test_get_with_nested_list dask/tests/test_core.py::test_flatten dask/tests/test_core.py::test_has_tasks dask/tests/test_core.py::test_iskey dask/tests/test_core.py::test_preorder_traversal dask/tests/test_core.py::test_GetFunctionTestMixin_class dask/tests/test_core.py::TestGet::test_get_with_list_top_level dask/tests/test_core.py::test_subs_arbitrary_key dask/tests/test_core.py::TestGet::test_nested_tasks dask/tests/test_core.py::test_subs_with_surprisingly_friendly_eq dask/tests/test_core.py::test_get_dependencies_nested dask/tests/test_core.py::TestGet::test_get_stack_limit dask/tests/test_core.py::test_get_dependencies_task_none dask/tests/test_core.py::test_subs dask/tests/test_core.py::test_subs_no_key_data_eq dask/tests/test_core.py::test_get_dependencies_nothing dask/tests/test_core.py::test_quote dask/tests/test_core.py::TestGet::test_badkey dask/tests/test_core.py::TestGet::test_get_with_list dask/tests/test_core.py::test_get_deps dask/tests/test_core.py::test_literal_serializable dask/tests/test_core.py::test_ishashable dask/tests/test_core.py::TestGet::test_get_works_with_unhashables_in_values dask/tests/test_core.py::test_get_dependencies_many dask/tests/test_core.py::test_iskey_numpy_types dask/tests/test_core.py::test_get_dependencies_list dask/tests/test_core.py::test_get_dependencies_task