Skip to content

Path mappings and source not found

Symptom: the debugger stops, the Call Stack has frames, but no source is shown — or the wrong file opens, or breakpoints never bind at all.

All of these have one root cause: the debugger and the debuggee disagree about paths.

Why it happens

The adapter reports the path the code was compiled or executed with. If that path does not exist on your machine, there is nothing to open.

Situation Reported path Your path
PHP in Docker /app/src/Controller.php /home/me/project/src/Controller.php
Built in a container /build/src/main.rs /home/me/project/src/main.rs
Debugging on another machine /opt/app/main.go /home/me/project/main.go

The translation also runs the other way: breakpoints you set on your paths have to be sent as the paths the debuggee knows. Without a mapping they never match, which is why "breakpoints never bind" and "no source shown" are the same bug.

Fixing it for PHP

[profiles.docker.launch_arguments]
pathMappings = { "/app" = "${root}" }

Read it as container path = host path.

Do not guess the left side — ask:

docker compose exec php pwd
docker compose exec php ls /app

and compare with the mount in docker-compose.yml:

volumes:
  - .:/app          # host . -> container /app

The volume's right side is the container path, and that is the mapping's left side.

Several mounts need several mappings

pathMappings = { "/app" = "${root}", "/vendor-src" = "${root}/vendor" }

The longest matching prefix wins; order does not matter.

Fixing it for other adapters

Other adapters have their own key, passed through launch_arguments unchanged. CodeLLDB, for instance:

[profiles.remote.launch_arguments]
sourceMap = { "/build" = "${root}" }

Check the adapter's documentation for the exact name.

Reading the symptoms

Symptom What it points at
No source at all the reported path does not exist locally — no mapping
Right line number, wrong file the prefix maps to the wrong directory
Most files work, one directory does not a second mount with no mapping
Breakpoints never bind the same mismatch, seen from the other direction
Source appears for library code but not yours your code moved since the build

When there is no container involved

If everything runs locally and the source is still missing, the frame likely has no source to show:

  • a standard library compiled without debug information;
  • a dependency whose sources are not on this machine;
  • code that was moved or renamed after the binary was built.

The frame is still selectable and its variables may still be available — see Call Stack.

For Rust and C/C++, rebuilding after moving the project directory fixes the last case, since paths are baked into the binary at build time.

Verifying a fix

  1. Start the session and stop somewhere.
  2. The source panel should show your file, at your path.
  3. The Breakpoints panel should show filled circles rather than dimmed rings.

If breakpoints bind but the source is still missing, the mapping is right for the breakpoint direction and wrong for the display direction — recheck both sides for a typo.