Fusion Guide
intermediate9 min read

Debugging Scripts and Add-Ins in VS Code

Attach Visual Studio Code to Fusion, set breakpoints, read logs, add packages, set up type hints, and fix the most common API errors.

Overview#

Writing API code without a debugger means guessing. Fusion supports real debugging of Python scripts and add-ins through Visual Studio Code (VS Code) and the Microsoft Python extension. You can set breakpoints, inspect variables, step line by line, and evaluate expressions in the debug console while the script runs inside Fusion. This page sets up that workflow, shows what to do when the debugger will not attach, and lists the simpler logging techniques that remain useful when a debugger is not practical.

Fusion bundles its own Python. Autodesk's documentation says that when you edit or debug a Python script or add-in, Fusion uses VS Code, and that debugging needs the Microsoft ms-python.python extension, which Fusion installs automatically the first time it opens VS Code. > Note: not confirmed in Autodesk's documentation: how the debugger connects (earlier drafts of this page described debugpy and a local port, launch.json keys and stub-file locations; none of that is in the mirror, so it is now marked as general guidance where it remains).

Where to find it#

  • In the Scripts and Add-Ins dialog, select a script or add-in and click Edit in code editor (pencil). Fusion opens the item in VS Code. (In the old dialog the Debug entry in the Run drop-down "does the same thing as Edit".) Then start debugging from VS Code.
  • In VS Code, the Python extension (ms-python.python) is installed for you by Fusion on first use.
  • The Text Commands window (Autodesk's help lists a Show/Hide Text Commands command; the palette id is TextCommands) shows app.log output.
  • TypeScript: you "must first edit the script from Fusion before debugging it", which starts the debug server and updates the VS Code workspace configuration. C++ is debugged with Visual Studio or Xcode (see the C++ page).

Step by step#

1. Install the tooling#

  1. You do not need to install anything by hand: the first time you choose Edit on a Python script, Fusion offers to install VS Code, and the first time VS Code starts from Fusion it installs the Python extension. When the VS Code install finishes, repeat the Edit step.
  2. You do not need a system Python for Fusion scripts; the interpreter is Fusion's.

2. Start debugging#

  1. Open Scripts and Add-Ins, select your script and click Edit in code editor so it opens in VS Code.
  2. Click the left edge of the code window to add a breakpoint where you want execution to stop.
  3. Start debugging with Run > Start Debugging or F5. Fusion starts executing your script and stops at the first breakpoint it hits.
  4. When you have finished, click Disconnect to end the session (Autodesk: "you'll need to click this button to stop debugging"). You can then edit and debug again; a script can be stopped and restarted repeatedly from VS Code.
  5. While stopped, Fusion's UI is unresponsive because the script runs on Fusion's main thread.

3. Step and inspect#

Use the debug toolbar or shortcuts:

ActionShortcutEffect
ContinueF5Run to next breakpoint
Step overF10Run the current line, not entering calls
Step intoF11Enter the called function (your own code only; API internals are native)
Step outShift+F11Finish the current function
RestartCtrl+Shift+F5Autodesk says restart "doesn't currently work with Fusion Scripts or Add-Ins"; disconnect and start again
Disconnect / StopShift+F5End the debugging session

While paused:

  • The Variables panel shows locals and globals. Expand design to see properties such as rootComponent; expand collections to see items.
  • The Watch panel evaluates expressions you type, like root.bRepBodies.count.
  • The Debug Console is a live Python prompt in the paused frame. You can call app.log('hi'), ui.messageBox('x'), and even create geometry. Be careful: changes you make here affect the open document.
  • Conditional breakpoints: right-click a red dot > Edit Breakpoint > Expression, such as body.name == 'Base', to pause only in specific iterations.
  • Logpoints: right-click the gutter > Add Logpoint to print a message without editing code, such as {sketch.name} has {sketch.profiles.count} profiles.

Tip: Stepping into a call such as extrudes.add(ext_input) will not show inner code; Fusion's API is a native layer. Instead inspect inputs before the call and results after.

4. Debug an add-in#

Autodesk's procedure for add-ins:

  1. While writing the add-in, uncheck Run on Startup, and make sure the add-in is not already running (a running add-in has the wheel icon). If it is, stop it.
  2. Start debugging from VS Code as for a script. Fusion loads the add-in and calls run, which typically builds the UI and connects events and then appears to be done; the add-in is still running, waiting for an event.
  3. Switch to Fusion and run the add-in's command. Breakpoints in the command-created handler are now hit.
  4. To debug stop, use Stop in the Scripts and Add-Ins dialog; Fusion calls stop and your breakpoints there are hit.
  5. If you disconnect the debugger or are forced to stop, the add-in keeps running in Fusion; stop it from the dialog. If you start debugging it again, Fusion calls its stop method before starting the new session.

General guidance, not Autodesk data: Python caches imported modules, so if you split your code across modules and edits are not picked up, importlib.reload(commands) at the top of run can help during development. Remove it from released code.

Environment, packages, and type hints#

Autocomplete and type hints#

Autodesk's Python topic explains the code-hint problem: the editor knows that Application.get() returns an Application, but properties typed as a base class (activeProduct returns Product; Selection.entity returns Base) only show base-class members. Two fixes: a type hint, which only helps the editor and checks nothing at run time (if the Manufacture workspace is active, des would hold a CAM product and fail later), or cast, which returns None when the type does not match:

des: adsk.fusion.Design = app.activeProduct                 # editor hint only
design = adsk.fusion.Design.cast(app.activeProduct)         # runtime check, None if not a Design
edge = adsk.fusion.BRepEdge.cast(ui.activeSelections[0].entity)

Note: not confirmed in Autodesk's documentation: stub-file names and python.analysis.extraPaths settings that earlier drafts described. The TypeScript template ships .d.ts definitions instead.

Third-party packages#

Autodesk: "The Python provided with Fusion includes only the core modules that come with a standard installation of Python." The recommended approach is not to add modules to sys.path but to keep a local copy of the module inside your script's folder or a subfolder (Autodesk's example is xlrd under a Modules folder) and import it with a relative path:

from .Modules import xlrd

General guidance, not Autodesk data: pure-Python packages are the safe choice, pip install --target from a system Python can fill such a folder, and compiled packages must match Fusion's Python version and platform, which the documentation does not state. The standard library (json, csv, urllib.request, zipfile, sqlite3, threading, pathlib, xml.etree) covers most needs.

Check which interpreter you are running with a one-off script that logs sys.executable and sys.version.

Logging and diagnosis without a debugger#

TechniqueHowUse when
Text Commandsapp.log('...')Quick checks
Message boxui.messageBox(str)Blocking, small amounts
Traceback displaytraceback.format_exc() in exceptAlways in run
File loggingopen(path, 'a')Add-ins, event code, crash analysis
logging moduleA FileHandler writing to a known pathLarger add-ins
Fusion logapp.log can write to the Fusion app log file as well as the Text Commands windowCrashes
Windows-only debug boxctypes.windll.user32.MessageBoxW(None, 'text', 'title', 1)Worker threads, where ui.messageBox can crash Fusion

Common errors and what they mean#

General guidance, not Autodesk data: the error texts below are typical symptoms, not messages quoted from the documentation. In Python an API failure raises RuntimeError; in C++ you call getLastError.

MessageLikely causeFix
RuntimeError: 3 : invalid argument ...Wrong type or value passed to an API callPrint the argument types; check units
RuntimeError: 2 : InternalValidationError : ...Fusion rejected the operation (invalid profile, failed feature)Examine the geometry state; try the same step manually
AttributeError: 'NoneType' object has no attribute ...A find or cast returned NoneCheck itemByName, Design.cast results
NameError for adskMissing importAdd import adsk.core, adsk.fusion
ModuleNotFoundErrorA local module name or path wrongCheck sys.path, package structure
TypeError: ... must be a ... objectPassing a Python list where an ObjectCollection or API object is expectedBuild an ObjectCollection
Button does nothingHandler garbage collectedStore handlers in a module list
"id already exists" style errorsAdd-in not cleaned up on stopRemove controls and definitions
Edit does nothingVS Code not installed or extension missingLet Fusion install them, repeat Edit

Treat the text after any numeric error code as the useful part.

Options reference#

What Autodesk documents about the debug setup:

ItemBehaviourSource
Edit in code editorOpens the item in VS Code (Python, TypeScript) or its project file (C++)Creating Scripts and Add-Ins
ms-python.python extensionRequired for Python debugging; installed automatically on first usePython Specific Issues
Start DebuggingRun > Start Debugging or F5Python Specific Issues
DisconnectEnds the session; required before debugging againPython Specific Issues
RestartDoes not currently work with Fusion scripts or add-insPython Specific Issues
Run on StartupUncheck while developing an add-inPython Specific Issues
C++ on WindowsVisual Studio: Debug > Attach to Process, "Native code", Fusion360.exe, then run from Scripts and Add-InsC++ Specific Issues
C++ on MacXcode: Debug > Attach to Process, "Autodesk Fusion"C++ Specific Issues

Note: not confirmed in Autodesk's documentation: the contents of a generated .vscode/launch.json (type, request, port, pathMappings, justMyCode). Open the file in a fresh template if you need it.

Tips and pitfalls#

Tip: Keep a dedicated "scratch" script with the debug setup so you can test small API calls in the Debug Console quickly: set a breakpoint at the end, then explore live.

Tip: Use Design.cast, Sketch.cast, and similar and check for None to produce friendly messages rather than cryptic attribute errors.

Warning: While paused at a breakpoint Fusion is unresponsive. Do not click in Fusion while paused; resume first. If you stop the debug session while the script is mid-operation, the document may be left half-modified. Use undo (Ctrl+Z) and check the timeline.

Warning: Do not leave debug-only code such as importlib.reload or hardcoded paths in releases you distribute.

Warning: General guidance, not Autodesk data: if debugging fails from a folder with spaces or non-ASCII characters in its path, try the item from a simple path like C:\dev\MyAddin.

Practice exercise#

  1. Create a script that loops over design.rootComponent.sketches and counts total sketch curves.
  2. Click Edit, start debugging with F5, set a breakpoint inside the loop, add a conditional expression sk.sketchCurves.count > 5.
  3. When it stops, use the Watch panel to evaluate sk.name and sk.profiles.count, then in the Debug Console run app.log(sk.name).
  4. Add a logpoint reporting {sk.name} without editing the file.

Expected result: the debugger pauses only on sketches with more than five curves, the Watch values match the browser, and the Text Commands window shows the log line.

  • Scripts and Add-Ins dialog
  • Event handlers
  • Packaging and distributing add-ins
  • C++ API notes

Sources

Checked against these Autodesk help topics (opens autodesk.com):

Related pages