Attach the VS Code debugger to Adobe UXP plugins (Photoshop, InDesign, XD, …) with full source-map support.
Requirements
- VS Code 1.85 or newer
- Adobe UXP Developer Tools (UDT) installed
- Some Adobe application to load UXP plugin into
- The UXP plugin loaded in the host application (via UDT)
Setup
1. Install the extension
Install the .vsix file from the Releases page via Extensions → ⋯ → Install from VSIX…, or:
code --install-extension vscode-uxp-debugger-*.vsix
2. Patch the UXP Developer Tools (one-time)
The extension discovers running plugin sessions via a .uxprc file that UDT writes next to your manifest.json. By default UDT does not write this file — a one-time patch to app.asar enables it. This file is in protected folder so we will use little trick to go around that.
- Make sure to quit UDT if it is running.
- On both Windows & MacOS you need to patch file
app.asar. So go to the UDT location- Windows:
C:\Program Files\Adobe\Adobe UXP Developer Tools\resources - macOS:
/Applications/Adobe UXP Developer Tools/Contents/Resources
- Windows:
- Move
app.asarfile to your desktop using Explorer/Finder - Most likely OS will ask you elevate permissions to do that so confirm the dialog
- Open the Command Palette in VSCode (
Ctrl+Shift+P/Cmd+Shift+P) and run:UXP: Patch app.asar (Persist .uxprc) - Select
app.asarin your desktop directory and wait for patcher to finish - Now you should see
app.asar(patched) andapp.asar.bak(original file for backup reasons) on your desktop - Move both files back into original location (OS will ask again for permission)
- Windows:
C:\Program Files\Adobe\Adobe UXP Developer Tools\resources - macOS:
/Applications/Adobe UXP Developer Tools/Contents/Resources
- Windows:
The patch is idempotent — safe to run multiple times. A .bak backup is created on the first run.
After patching, restart the UXP Developer Tools application.
Troubleshooting
If something goes wrong with UDT delete app.asar and rename app.asar.bak to app.asar so original file will be restored. If there are still issues
please uninstall with Creative Cloud Desktop app. Check the UDT directory for remaining files and remove them if any. Then install UDT again.
Alternative Method. Load the plugin via UDT CLI (for experts)
Show details
Use the uxp CLI (not included with UDT) to load your plugin into the host app. This generates the .uxprc session file that the debugger reads.
Run in first terminal
uxp service start
And in second terminal
uxp plugin load
Run this from your plugin directory (where manifest.json is). The .uxprc file will appear next to manifest.json after the plugin is loaded.
This option is not very ergonomic. Has several disadvantages and I recommend it only for experts if there are special requirements.
Attaching the Debugger
Option A — Command Palette
- Make sure the host application (e.g. Photoshop) is running with your plugin loaded.
- Open the Command Palette and run
UXP: Attach to Adobe UXP Plugin. - First time: choose "Select new target…" and pick your
manifest.json. - Subsequent runs: your recent targets appear in the list — just pick one.
- If multiple debug targets are found, a second pick list lets you select the right one.
- The debug session starts automatically.
The extension remembers up to 20 recently used targets, sorted by last use. Entries whose manifest.json has been deleted are removed automatically.
Option B — launch.json
Add a configuration to .vscode/launch.json:
{
"configurations": [
{
"type": "uxp",
"request": "attach",
"name": "Attach to UXP Plugin",
"manifestPath": "${workspaceFolder}/manifest.json"
}
]
}
Press F5 (or choose the configuration from the Run & Debug panel). VS Code substitutes ${workspaceFolder} and other variables before passing the path to the extension.
Option C — .debug.json (fixed port) - not recommended
Show details If you prefer not to use the UDT relay, you can pin a fixed CDP debug port by placing manually a `.debug.json` file next to `manifest.json`:
{ "port": 9917 }
The extension will probe that port directly via /json/list instead of using the UDT relay. Both methods can coexist.
This will work only in older versions of host apps.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "No running UXP targets found" | Plugin not loaded, or wrong manifest.json |
Start UDT, load plugin and make sure the host app is open |
| "Connected to the relay but no response from the plugin" — session disconnects after 8 s | Plugin load succeeded but the UXP runtime never sent a ready signal | Unload the plugin and load again via "Load button" in UDT and try again |
| "manifest.json not found" | Path in launch.json is wrong |
Check the manifestPath value; make sure ${workspaceFolder} resolves to the right folder |
| "A UXP debug session is already active" | Tried to attach while already debugging | Click Detach and reconnect to replace the existing session, or cancel |
| "Failed to start the JS debug session" | Internal pwa-node attach error |
Check the UXP Debugger output channel for details |
| "Permission denied" during patch | app.asar owned by another user |
Follow patching instructions above |
.uxprc not created after plugin load |
app.asar not yet patched |
Follow patching instructions above |
How It Works
The extension does not implement a custom debug adapter. Instead it:
- Discovers running targets via two methods:
.uxprc— reads the UDT session file and connects viaws://127.0.0.1:14001/socket/cdt/<sessionId>.debug.json— reads a pinned port and probeshttp://127.0.0.1:<port>/json/list
- Starts a lightweight CDP proxy between VS Code and the UXP endpoint, translating protocol quirks (source-map root rewriting,
Runtime.evaluatecontext patching,NodeWorker.enablesuppression). - Delegates to the built-in VS Code JS debugger (
pwa-nodeattach mode) which handles all actual protocol work.
Project Structure
src/
extension.ts Entry point; registers commands and debug provider
debugConfigProvider.ts Handles launch.json "uxp" type; substitutes variables
cdpProxy.ts CDP proxy (WebSocket + HTTP); message rewriting
uiHelpers.ts pickTarget() QuickPick
constants.ts / types.d.ts Shared constants and types
patch-asar.ts ASAR patch logic (idempotent, streaming)
commands/
attach.ts Main attach flow + target history
patchAsar.ts Patch command UI
setManifestPath.ts Manifest path picker
endpointDetection/
discoverViaDebugJson.ts .debug.json → /json/list probe
discoverViaUxpRc.ts .uxprc → UDT relay WebSocket
License
MIT