Skip to content

v2.0.0a3 -- cryptic error message on type errors for server commands #548

@itsmeknt

Description

@itsmeknt

Hello! I have a small QoL request.

I am using the v2 feature where we can introduce type annotations to our server commands.

If my server commands include some types Pygls doesn't support, it gives a cryptic error message. For example, if the server command is:

@attrs.define
class EvaluateSumArgs:
    """Represents the arguments to pass to the ``codeLens.evaluateSum`` command"""

    ids: list[str]  # this is OK and works
    context: dict[str, Any]  # this does not work and throws an exception
    my_object: CustomObject  # this also throws an exception

Then the terminal will give an unhelpful error in trying to serialize this command definition:

Ignoring notification for unknown method 'workspace/didChangeConfiguration'                                                                                                                                                                                                                                                                                                                                                             
Exception occurred for message "4"                                                                                                                                                                                                                                                                                                                                                                                                      
  + Exception Group Traceback (most recent call last):                                                                                                                                                                                                                                                                                                                                                                                  
  |   File "/home/kevin/workspace/toxidious/venv/lib/python3.13/site-packages/pygls/protocol/language_server.py", line 328, in lsp_workspace__execute_command                                                                                                                                                                                                                                                                           
  |     args, kwargs = _prepare_command_arguments(handler, params, self._converter)                                                                                                                                                                                                                                                                                                                                                     
  |                    ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                                                                                                                                                                                                     
  |   File "/home/kevin/workspace/toxidious/venv/lib/python3.13/site-packages/pygls/protocol/language_server.py", line 395, in _prepare_command_arguments                                                                                                                                                                                                                                                                               
  |     value = converter.structure(next(param_vals), ptype)                                                                                                                                                                                                                                                                                                                                                                            
  |   File "/home/kevin/workspace/toxidious/venv/lib/python3.13/site-packages/cattrs/converters.py", line 558, in structure                                                                                                                                                                                                                                                                                                             
  |     return self._structure_func.dispatch(cl)(obj, cl)                                                                                                                                                                                                                                                                                                                                                                               
  |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^                                                                                                                                                                                                                                                                                                                                                                               
  |   File "<cattrs generated structure toxidious.language_server.command.command_request.CommandRequest>", line 64, in structure_CommandRequest                                                                                                                                                                                                                                                                                        
  |     if errors: raise __c_cve('While structuring ' + 'CommandRequest', errors, __cl)                                                                                                                                                                                                                                                                                                                                                 
  |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                                                                                                                                                                                                 
  | cattrs.errors.ClassValidationError: While structuring CommandRequest (1 sub-exception)                                                                                                                                                                                                                                                                                                                                              
  +-+---------------- 1 ----------------                                                                                                                                                                                                                                                                                                                                                                                                
    | Traceback (most recent call last):                                                                                                                                                                                                                                                                                                                                                                                                
    |   File "<cattrs generated structure toxidious.language_server.command.command_request.CommandRequest>", line 60, in structure_CommandRequest                                                                                                                                                                                                                                                                                      
    |     res['context'] = __c_structure_context(o['context'], __c_type_context)                                                                                                                                                                                                                                                                                                                                                        
    |                      ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                                                                                                                                                                                                        
    |   File "", line 3, in structure_mapping                                                                                                                                                                                                                                                                                                                                                                                           
    | AttributeError: 'NoneType' object has no attribute 'items'                                                                                                                                                                                                                                                                                                                                                                        
    | Structuring class CommandRequest @ attribute context                                                                                                                                                                                                                                                                                                                                                                              
    +------------------------------------                                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                                                                                        
During handling of the above exception, another exception occurred:                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                                                                        
Traceback (most recent call last):                                                                                                                                                                                                                                                                                                                                                                                                      
  File "/home/kevin/workspace/toxidious/venv/lib/python3.13/site-packages/pygls/protocol/json_rpc.py", line 268, in _send_handler_result                                                                                                                                                                                                                                                                                                
    self._send_response(msg_id, result=future.result())                                                                                                                                                                                                                                                                                                                                                                                 
                                       ~~~~~~~~~~~~~^^                                                                                                                                                                                                                                                                                                                                                                                  
  File "/usr/lib/python3.13/concurrent/futures/_base.py", line 449, in result                                                                                                                                                                                                                                                                                                                                                           
    return self.__get_result()                                                                                                                                                                                                                                                                                                                                                                                                          
           ~~~~~~~~~~~~~~~~~^^                                                                                                                                                                                                                                                                                                                                                                                                          
  File "/usr/lib/python3.13/concurrent/futures/_base.py", line 401, in __get_result                                                                                                                                                                                                                                                                                                                                                     
    raise self._exception                                                                                                                                                                                                                                                                                                                                                                                                               
  File "/home/kevin/workspace/toxidious/venv/lib/python3.13/site-packages/pygls/protocol/json_rpc.py", line 242, in _run_generator                                                                                                                                                                                                                                                                                                      
    handler, args, kwargs = gen.send(value)                                                                                                                                                                                                                                                                                                                                                                                             
                            ~~~~~~~~^^^^^^^                                                                                                                                                                                                                                                                                                                                                                                             
  File "/home/kevin/workspace/toxidious/venv/lib/python3.13/site-packages/pygls/protocol/language_server.py", line 330, in lsp_workspace__execute_command                                                                                                                                                                                                                                                                               
    raise JsonRpcInvalidParams.of(exc)                                                                                                                                                                                                                                                                                                                                                                                                  
pygls.exceptions.JsonRpcInvalidParams: Invalid Params: While structuring CommandRequest (1 sub-exception)                     

The small QoL update I'd like to request is to make this error message more helpful, so that us developers can more easily tell if it is a command type issue or something else.

Additionally, would it be possible to extend the serializer so that we can add any custom type we want to the server command? I imagine supporting dict[primitive, primitive] would be very helpful, and for now I am just manually calling json.dumps() and json.loads() everytime I need a dict in the command.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions