You can kinda hack this with Python 3.11+, since the traceback contains fine-grained information about where the error happened.
import ast
import linecache
import traceback
data = {"my_key": "my_value"}
flurk = data
try:
    data["flep"] = data["my_key"] + flurk["unknown_key"]
except KeyError as e:
    # Find the last frame where the exception occurred, formatted as a FrameSummary
    err_frame = traceback.TracebackException.from_exception(e).stack[-1]
    if err_frame.lineno == getattr(err_frame, "end_lineno", -1):  # If we can reliably find the line,
        # ... read the line,
        line = linecache.getline(err_frame.filename, err_frame.lineno)
        # find the "marked segment" in it,
        fragment = line[err_frame.colno:err_frame.end_colno]
        # ... and parse it as an expression.
        expr: ast.Expression = ast.parse(fragment, mode='eval')
        # Check we're dealing with a subscript (index) node...
        assert isinstance(expr.body, ast.Subscript)
        # ... and extract the main parts of the expression.
        subscriptee = ast.unparse(expr.body.value)
        subscript = ast.unparse(expr.body.slice)
    else:
        subscriptee = None  # No idea
        subscript = e.args[0]  # Just use the exception message
    raise RuntimeError(f"KeyError with {subscriptee=!r}, {subscript=!r}") from e
prints out
Traceback (most recent call last):
  File "scratch_679.py", line 8, in <module>
    data["flep"] = data["my_key"] + flurk["unknown_key"]
                                    ~~~~~^^^^^^^^^^^^^^^
KeyError: 'unknown_key'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "scratch_679.py", line 27, in <module>
    raise RuntimeError(f"KeyError with {subscriptee=!r}, {subscript=!r}") from e
RuntimeError: KeyError with subscriptee='flurk', subscript="'unknown_key'"
so you can see the subscriptee name is flurk.