Repository: microsoft/ptvsd

Issue:
Errors in debugger when debugging
**Note:** This is an error reported by a user of the VS Code experimental debugger.

Original error reported here https://github.com/Microsoft/vscode-python/issues/177#issuecomment-386674497

`
Traceback (most recent call last): File "/home/thiago/.vscode/extensions/ms-python.python-2018.4.0/pythonFiles/experimental/ptvsd/ptvsd/wrapper.py", line 796, in done fut.result() File "/home/thiago/.vscode/extensions/ms-python.python-2018.4.0/pythonFiles/experimental/ptvsd/ptvsd/futures.py", line 40, inresult reraise(self._exc_info) File "/home/thiago/.vscode/extensions/ms-python.python-2018.4.0/pythonFiles/experimental/ptvsd/ptvsd/reraise3.py", line 8, inreraise raise exc_info[1].with_traceback(exc_info[2]) File "/home/thiago/.vscode/extensions/ms-python.python-2018.4.0/pythonFiles/experimental/ptvsd/ptvsd/futures.py", line 149, in callback x = next(it) File "/home/thiago/.vscode/extensions/ms-python.python-2018.4.0/pythonFiles/experimental/ptvsd/ptvsd/wrapper.py", line 1229, in on_variables pyd_var = self.var_map.to_pydevd(vsc_var) File "/home/thiago/.vscode/extensions/ms-python.python-2018.4.0/pythonFiles/experimental/ptvsd/ptvsd/wrapper.py", line 215, in to_pydevd return self._vscode_to_pydevd[vscode_id] KeyError: 125
`


Discussion:
This could happen because Scopes request failed for some reason and the following variables request failed because of that. Or Variables request occurred before Scopes request. Another possibility is that it was a collection object that did not get added to the variables map.

Either way I think we should fail the request with `send_error_response` if we cannot find it in the `var_map`.

Resolving patch:
diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py
--- a/ptvsd/wrapper.py
+++ b/ptvsd/wrapper.py
@@ -1292,7 +1292,11 @@ def on_variables(self, request, args):
         vsc_var = int(args['variablesReference'])
         fmt = args.get('format', {})
 
-        pyd_var = self.var_map.to_pydevd(vsc_var)
+        try:
+            pyd_var = self.var_map.to_pydevd(vsc_var)
+        except KeyError:
+            self.send_error_response(request)
+            return
 
         if len(pyd_var) == 3:
             cmd = pydevd_comm.CMD_GET_FRAME
@@ -1383,7 +1387,11 @@ def on_setVariable(self, request, args):
         """Handles DAP SetVariableRequest."""
 
         vsc_var = int(args['variablesReference'])
-        pyd_var = self.var_map.to_pydevd(vsc_var)
+        try:
+            pyd_var = self.var_map.to_pydevd(vsc_var)
+        except KeyError:
+            self.send_error_response(request)
+            return
 
         var_name = args['name']
         var_value = args['value']


Test patch:
diff --git a/tests/highlevel/test_messages.py b/tests/highlevel/test_messages.py
--- a/tests/highlevel/test_messages.py
+++ b/tests/highlevel/test_messages.py
@@ -449,6 +449,25 @@ class MyType(object):
             self.expected_pydevd_request('{}\t2\tFRAME'.format(thread.id)),
         ])
 
+    def test_invalid_var_ref(self):
+        with self.launched():
+            with self.hidden():
+                _, thread = self.pause('t', *[
+                    # (pfid, func, file, line)
+                    (2, 'spam', 'abc.py', 10),  # VSC frame ID 1
+                    (5, 'eggs', 'xyz.py', 2),  # VSC frame ID 2
+                ])
+            self.send_request(
+                # should NOT match variable or frame ID
+                variablesReference=12345,
+            )
+            received = self.vsc.received
+
+        self.assert_vsc_received(received, [
+            self.expected_failure(''),
+            # no events
+        ])
+
     def test_container(self):
         self.PYDEVD_CMD = CMD_GET_FRAME
         with self.launched():
@@ -570,6 +589,27 @@ def test_local(self):
                 '{}\t2\tLOCAL\tspam\t1'.format(thread.id)),
         ])
 
+    def test_invalid_var_ref(self):
+        with self.launched():
+            with self.hidden():
+                _, thread = self.pause('t', *[
+                    # (pfid, func, file, line)
+                    (2, 'spam', 'abc.py', 10),  # VSC frame ID 1
+                    (5, 'eggs', 'xyz.py', 2),  # VSC frame ID 2
+                ])
+            self.send_request(
+                # should NOT match any variable or frame ID
+                variablesReference=12345,
+                name='spam',
+                value='eggs',
+            )
+            received = self.vsc.received
+
+        self.assert_vsc_received(received, [
+            self.expected_failure(''),
+            # no events
+        ])
+
     def test_container(self):
         with self.launched():
             with self.hidden():