Repository: microsoft/ptvsd

Issue:
Return error messages in the response for a failed debugger protocol request
I've found at least one case where a certain debugger protocol request fails and a failure response is sent back, however there's no additional information on the failure.
Ideally we should return some more information about the cause of the failure, some error message.
This should help diagnosing issues.

For reference see https://github.com/Microsoft/ptvsd/issues/825


Discussion:

Resolving patch:
diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py
--- a/ptvsd/wrapper.py
+++ b/ptvsd/wrapper.py
@@ -1512,7 +1512,7 @@ def on_threads(self, request, args):
         try:
             xml = self.parse_xml_response(resp_args)
         except SAXParseException as ex:
-            self.send_error_response(request)
+            self.send_error_response(request, resp_args)
             return
 
         try:
@@ -1594,8 +1594,10 @@ def on_stackTrace(self, request, args):
         try:
             pyd_tid = self.thread_map.to_pydevd(vsc_tid)
         except KeyError:
-            # Unknown thread, nothing much we cna do about it here
-            self.send_error_response(request)
+            # Unknown thread, nothing much we can do about it here
+            self.send_error_response(
+                request,
+                'Thread {} not found'.format(vsc_tid))
             return
 
         try:
@@ -1705,7 +1707,9 @@ def on_variables(self, request, args):
         try:
             pyd_var = self.var_map.to_pydevd(vsc_var)
         except KeyError:
-            self.send_error_response(request)
+            self.send_error_response(
+                request,
+                'Variable {} not found in frame'.format(vsc_var))
             return
 
         if len(pyd_var) == 3:
@@ -1720,7 +1724,7 @@ def on_variables(self, request, args):
         try:
             xml = self.parse_xml_response(resp_args)
         except SAXParseException as ex:
-            self.send_error_response(request)
+            self.send_error_response(request, resp_args)
             return
 
         try:
@@ -1818,13 +1822,15 @@ def on_setVariable(self, request, args):
         if var_name.startswith('(return) '):
             self.send_error_response(
                 request,
-                'Cannot change return value.')
+                'Cannot change return value')
             return
 
         try:
             pyd_var = self.var_map.to_pydevd(vsc_var)
         except KeyError:
-            self.send_error_response(request)
+            self.send_error_response(
+                request,
+                'Variable {} not found in frame'.format(vsc_var))
             return
 
         lhs_expr = self._get_variable_evaluate_name(pyd_var, var_name)
@@ -1860,7 +1866,7 @@ def on_setVariable(self, request, args):
         try:
             xml = self.parse_xml_response(resp_args)
         except SAXParseException as ex:
-            self.send_error_response(request)
+            self.send_error_response(request, resp_args)
             return
 
         try:
@@ -1899,7 +1905,7 @@ def on_evaluate(self, request, args):
         try:
             xml = self.parse_xml_response(resp_args)
         except SAXParseException as ex:
-            self.send_error_response(request)
+            self.send_error_response(request, resp_args)
             return
 
         try:
@@ -2240,7 +2246,9 @@ def on_completions(self, request, args):
         try:
             pyd_tid, pyd_fid = self.frame_map.to_pydevd(vsc_fid)
         except KeyError:
-            self.send_error_response(request)
+            self.send_error_response(
+                request,
+                'Frame {} not found'.format(vsc_fid))
 
         cmd_args = '{}\t{}\t{}\t{}'.format(pyd_tid, pyd_fid, 'LOCAL', text)
         _, _, resp_args = yield self.pydevd_request(


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
@@ -393,12 +393,14 @@ def test_unknown_thread(self):
         with self.launched():
             with self.hidden():
                 tid, _ = self.set_thread('x')
-            req = self.send_request(
-                threadId=tid + 1,
+            self.send_request(
+                threadId=12345,
             )
             received = self.vsc.received
 
-        self.assert_vsc_failure(received, [], req)
+        self.assert_vsc_received(received, [
+            self.expected_failure('Thread 12345 not found'),
+        ])
         self.assert_received(self.debugger, [])
 
 
@@ -528,7 +530,7 @@ def test_invalid_var_ref(self):
             received = self.vsc.received
 
         self.assert_vsc_received(received, [
-            self.expected_failure(''),
+            self.expected_failure('Variable 12345 not found in frame'),
             # no events
         ])
 
@@ -670,7 +672,7 @@ def test_invalid_var_ref(self):
             received = self.vsc.received
 
         self.assert_vsc_received(received, [
-            self.expected_failure(''),
+            self.expected_failure('Variable 12345 not found in frame'),
             # no events
         ])