Skip to content

VSCode Remote SSH: Rich traceback links point to local filesystem instead of remote server #4036

@yaokunxu

Description

@yaokunxu

I've checked docs and closed issues for possible solutions.
I can't find my issue in the FAQ.


Describe the issue

When using Rich to render tracebacks in a VSCode Remote SSH development environment, the clickable file links in the traceback output point to the local filesystem path (e.g., file:///home/user/...) instead of the correct VSCode Remote SSH URI (e.g., vscode-remote://ssh-remote+server-name/home/user/...).

This causes VSCode to attempt opening the file on the local machine (which does not exist), resulting in a "System cannot find the file specified (0x2)" error, instead of navigating to the corresponding file on the remote server.

To Reproduce

  1. Set up a VSCode Remote SSH connection to an Ubuntu 20.04 server.
  2. In the remote environment, install rich==14.3.3 and Python 3.12.11.
  3. Run a Python script that triggers an uncaught exception, with Rich's traceback handler installed:
    from rich.traceback import install install(show_locals=True) # Trigger an exception 1 / 0
  4. Observe the traceback output in the VSCode terminal.
  5. Click on any file path link (e.g., test.py:5).

Expected behavior: The link opens the file at the correct line number in the VSCode Remote SSH window (pointing to the server's filesystem).
Actual behavior: VSCode attempts to open the path on the local machine, failing with a file not found error.

Screenshots

Image

(Shows the "Failed to open: 系统找不到指定的文件。(0x2)" dialog after clicking a traceback link)

Platform

  • rich==14.3.3
  • Python==3.12.11
  • OS: Ubuntu 20.04.6 LTS (Server, accessed via VSCode Remote SSH)
  • VSCode Version: 1.107.1
  • Local OS: Windows 11 (client machine)

Additional context

  • The issue occurs specifically in the VSCode Remote SSH context. Running the same code locally works correctly (links point to the local filesystem).
  • VSCode injects the VSCODE_REMOTE_NAME environment variable into the remote shell, which contains the server alias (e.g., my-server). A correct remote URI would be vscode-remote://ssh-remote+{VSCODE_REMOTE_NAME}{absolute_file_path}#L{line_number}.
  • The current implementation of rich.traceback generates only file:// links, which do not respect the VSCode Remote environment.

Possible root cause

The rich.traceback module's path formatting logic does not detect the VSCode Remote SSH environment and does not generate the vscode-remote:// protocol links required for correct file navigation in this setup.

P.S. This is my logging.py file。 I would be pleased to provide any additional information or assistance you might need. Thank you for your time and consideration. I appreciate any feedback you can provide.

 import logging from datetime import datetime from rich.theme import Theme from rich.console import Console from rich.logging import RichHandler custom_theme = Theme( { "info": "cyan", "warning": "yellow", "error": "bold red", "critical": "bold white on red", "debug": "dim cyan", "success": "bold green", } ) def setup_logger( name: str = None, level: str = "INFO", log_file: str = None, rich_tracebacks: bool = True, ) -> logging.Logger: logger = logging.getLogger(name) logger.setLevel(getattr(logging, level.upper())) if logger.handlers: return logger console_handler = RichHandler( console=Console(theme=custom_theme), rich_tracebacks=rich_tracebacks, tracebacks_show_locals=True, show_time=True, show_path=True, markup=True, ) console_handler.setLevel(getattr(logging, level.upper())) logger.addHandler(console_handler) if log_file: import os os.makedirs(os.path.dirname(log_file) or ".", exist_ok=True) file_handler = logging.FileHandler(log_file, encoding="utf-8") file_handler.setLevel(getattr(logging, level.upper())) file_formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) file_handler.setFormatter(file_formatter) logger.addHandler(file_handler) return logger def get_logger(name: str = None) -> logging.Logger: return logging.getLogger(name) def setup_experiment_logger( experiment_name: str, log_dir: str = "./logs", level: str = "INFO" ) -> logging.Logger: log_file = ( f"{log_dir}/{experiment_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" ) return setup_logger(experiment_name, level, log_file)

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