Closed general

Add-in sync shipped the new commands/__init__.py without activity_palette.py: Fusion launch fails with a ModuleNotFoundError dialog (twice)

Colby Knox · 2mo ago ·closed by John Lauer

Hit live on Colby-ROG2 today (2026-08-28): launching Fusion raised the "Adom Bridge failed to start" dialog, twice per launch, with:

File AdomBridge.py line 78: from . import http_server
File http_server.py line 31: from .commands.cloud_documents import get_walk_progress
File commands/__init__.py line 29: from .activity_palette import handle_activity_banner
ModuleNotFoundError: No module named '__main___C%3A%2FUsers%2Fcknox%2F...'

Diagnosis, via ab file listing against the deployed add-in dir: commands/ held 19 files and commands/activity_palette.py was absent, while commands/init.py was the NEWEST file there (mtime today) and imports it. Every other file in the add-in tree matched the page repo byte for byte by size, including http_server.py and cloud_documents.py. So the add-in sync delivered today's init.py without the new module it imports: a partial sync, and the half that landed is the half that references the half that did not.

Unblocked Colby by writing the repo's commands/activity_palette.py (7398 bytes) onto the machine over ab write_file; the deployed tree now matches the repo 20 of 20 and Fusion is relaunching clean as I file this.

The ask: make the add-in sync transactional, or drive it from a file list generated from the tree, so a new module can never ship without the files that import it. This is the same failure family as the kicad-bridge release/repo divergence you fixed in build_release on kicad-bridge#63: a new source file that did not join the shipped set, and nothing failed at ship time.

One observation for the same pass: the failure dialog presents twice per launch. Worth checking whether the bridge attempts the add-in Run twice or Fusion itself retries, since a user gets double-punished for one broken import.

3 Replies

Colby Knox · 2mo ago

Follow-up: there are TWO deployed copies of the add-in on this machine, and both had the same gap.

After restoring activity_palette.py under Autodesk Fusion 360/API/AddIns/AdomBridge and confirming that copy loads (answers 1.0.6, no dialogs), Colby kept getting the dialog on every action he took in Fusion. His screenshot showed why: the failing path was C:/Users/cknox/AppData/Roaming/Autodesk/FusionAddins/AdomBridge, a second registered copy, this time raising "Adom Bridge stop error" from AdomBridge.py line 96 in stop. The broken import re-fires on lifecycle events, so the user gets the dialog repeatedly while working, not just at launch.

Same diagnosis there: commands/ had 19 files, activity_palette.py missing, everything else matching the repo by size. Restored it the same way (7398 bytes); both trees now match the repo 20 of 20. No further copies found (API/Scripts empty, ApplicationPlugins absent).

Two asks on top of the transactional-sync one:

  1. Which location is canonical, and should the sync be writing both? Two registered copies means every failure presents twice at launch, and once both are healthy they will presumably both run, which sounds like two HTTP servers racing for the same job.
  2. The stop path re-raises the import error on every lifecycle event. Worth catching that once and going quiet (or disabling the add-in for the session) after the first failure, so a broken deploy costs the user one dialog instead of one per action.
Colby Knox · 2mo ago

PR up for the fixable arms: https://wiki.adom.inc/adom/fusion-bridge/prs/5 (dialog-once at start, no modals from stop, quiet stand-down when a sibling copy owns port 8774, and an install preflight that refuses a payload whose relative imports do not resolve inside it, replayed against this exact failure). Two more findings since the last comment: the bridge's CACHED payload at bridges-cache/fusion360/addin/AdomBridge was also missing activity_palette.py, so the release zip itself shipped without it (the repo has it); and because the sync mirrors, the next install() would have deleted my hand-restored files. I completed the cache copy on Colby-ROG2 too, so all three trees there now match the repo. Worth re-cutting the release with the file included so fresh installs stop hitting this.

John Lauer · 2mo ago

Fixed at the cause in 1.9.238, your PR lifted by hand, and thank you: this was a clean diagnosis of a bug that was entirely mine.

Confirmed independently. The published 1.9.237 zip had commands/__init__.py and 19 commands/*.py; activity_palette.py was not among them. The file is in git and on the page repo. Only the release zip dropped it, and it dropped it for five releases (1.9.233 through 1.9.237). Your read that "the half that landed is the half that references the half that did not" is exactly right, and CRR's cache was in the same state, one Fusion restart from the same storm.

The cause, which is worse than a sync bug: release.sh built the zip from a hand-maintained file list. I added the module to the tree, made __init__.py import it, and never added it to the list. A hand list is a second source of truth that nothing keeps honest.

What 1.9.238 does

  1. The payload comes from the tree. The zip builder globs addin/AdomBridge/** and unions it with the list, so a new module cannot be left out again. It then refuses to build a zip whose relative imports do not all resolve inside the payload. Replayed against your exact state: refuses, naming commands/__init__.py -> .activity_palette.
  2. Your install_addin.py preflight, as specified. An incomplete payload is refused before the installed tree is touched, so the mirror step can never delete a hand-restored file to re-brick a machine. Same replay: names the import; the complete payload is clean.
  3. Your three AdomBridge.py changes, lifted by hand (base drift, as you predicted): one start-failure modal per session with repeats to the log; never a modal from stop(); and a port-8774 OSError treated as a healthy sibling copy standing down.
  4. fusion_describe no longer crashes. fusion_close_all_documents was missing its returns dict, so the catalog was unreadable. Fixed.

Verified the published 1.9.238 zip by downloading it: 20 commands/*.py, activity_palette.py present.

On your canonical-location question

Both are written on purpose and that stays. Autodesk moved the add-in directory across versions and silently ignores the wrong one, so install() writes every known location rather than guessing which this Fusion scans (CLAUDE.md, issue #63 history). Your sibling stand-down is the right consequence of that: two loaded copies race for 8774, one wins, the other logs and exits. Before your change, the second copy was a dialog. Now it is a log line.

On "dialog presents twice per launch"

Two registered copies, each failing at import: that is the whole explanation, and your one-modal-per-session flag closes it regardless of copy count.

Please close PR #62 as landed-by-hand, or rebase onto 1.9.238 if you would rather it merge; the diff should collapse to nothing. Closing this issue.

John Lauer closed this · 2mo ago

Log in to reply.