YK
Projects

LeetCode Debugger - Debugging LeetCode Solutions in VS Code

2026-05-05

When solving problems on LeetCode, the submission result alone is often not enough to understand why the code is wrong.

For simple problems, I can insert a few print() statements. But once linked lists, trees, recursion, or two-pointer logic become involved, following how each value changes becomes difficult.

Since VS Code already has a Python debugger, I initially thought I could simply copy my LeetCode solution, set a breakpoint, and start debugging.

In reality, it was not that simple.

A LeetCode solution is not a complete program

A typical LeetCode submission contains only a Solution class.

1class Solution: 2 def twoSum(self, nums: list[int], target: int) -> list[int]: 3 ...

There is no main() function, no code that passes input to twoSum(), and no code that prints or validates the returned value. LeetCode’s server handles all of that behind the scenes.

To run the same code locally, I needed to recreate the missing steps.

Prepare the test input → Create the Solution instance → Find the method to execute → Pass the arguments → Run the method → Print and validate the result

Writing this setup for every problem would be inconvenient, so I created LeetCode Debugger to automate the process.

Using a matching test case file

I decided to place a test case file next to each solution file using the same base name.

two_sum.py two_sum.txt

The .txt file contains the input and expected output copied from LeetCode.

1Input: nums = [2,7,11,15], target = 9 2Output: [0,1]

When two_sum.py is open in VS Code, the extension automatically looks for two_sum.txt and uses it for the debug session.

If the file does not exist, the extension creates one with the following template.

1Input: 2Output:

Project structure

At first, I thought the VS Code extension could handle everything.

However, parsing test cases and executing a Python Solution class from JavaScript did not feel like a natural structure.

I eventually divided the project into two parts.

VS Code extension - Find the active Python file - Find the matching test case file - Create the debug configuration Python runtime - Parse the test cases - Execute the Solution method - Validate the result

The VS Code extension prepares the debug session, while the Python runtime recreates the parts of the LeetCode execution environment that the solution needs.

package.json

In a VS Code extension, package.json does more than describe a Node.js package. It also tells VS Code which features the extension provides.

This project registers two commands.

1LeetCode: Open Case File 2LeetCode: Debug Current Solution

They are available from the Command Palette and as buttons in the editor title bar when a Python file is open.

The extension also contributes a custom debugger type named leetcodeDebugger.

1{ 2 "name": "LeetCode: Debug Current Solution", 3 "type": "leetcodeDebugger", 4 "request": "launch" 5}

The first version could only start debugging through a command. After adding a dedicated debugger type, the extension began appearing in VS Code’s Run and Debug configuration picker and could also be launched with F5.

extension.js

extension.js connects VS Code to the Python runtime.

When a debug session starts, it checks the following conditions.

Is the active file a Python file? → Save it if it has unsaved changes Does a matching .txt file exist? → Ask whether to create one if it does not Is the Python Debugger extension installed? → Show an error if it is unavailable

Once everything is ready, the extension copies its Python runtime files into a temporary directory.

It then creates a debugpy configuration similar to this:

{ type: "debugpy", request: "launch", program: bootstrapPath, args: [ "--solution", solutionPath, "--case-file", caseFilePath ] }

One important detail is that the user’s solution file is not launched directly.

The program launched first = bootstrap_debug_session.py The file the user wants to debug = the LeetCode solution file

The bootstrap program loads and executes the solution, while the VS Code Python Debugger handles breakpoints inside the original solution file.

The internal runtime directory is excluded from normal stepping. As a result, pressing Step Into does not constantly move into test-case parsing code. The session remains focused on the user’s Solution implementation.

The complete execution flow

When the user presses F5, the following sequence occurs.

User └─ Presses F5 └─ VS Code extension ├─ Checks the active Python file ├─ Finds the matching test case file ├─ Prepares the Python runtime └─ Starts debugpy └─ bootstrap_debug_session.py └─ Starts the LeetCode Python runtime

The project does not implement a new Python debugger.

It is closer to an adapter that prepares a LeetCode solution so the existing VS Code Python Debugger can execute it.

In other words, pressing F5 means:

Find the current LeetCode solution and its test cases, prepare a LeetCode-compatible execution environment, and start the solution with the Python debugger.

Starting the debugger, however, is only part of the problem.

If Solution contains several methods, the runtime still needs to determine which one is the actual entry point. It must also convert values such as [1,2,3] into objects such as ListNode or TreeNode.

The next post covers the Python runtime that handles those problems.