From a145651cc02e6b68046dd04bf3e2afa4a9785d12 Mon Sep 17 00:00:00 2001 From: Jedrzej Kosinski Date: Tue, 24 Mar 2026 23:41:01 -0700 Subject: [PATCH] Track custom node startup errors and expose via API endpoint Store import and prestartup errors in NODE_STARTUP_ERRORS dict (nodes.py, main.py) and add GET /custom_node_startup_errors endpoint (server.py) so the frontend/Manager can distinguish failed imports from missing nodes. Ref: ComfyUI-Launcher#303 Amp-Thread-ID: https://ampcode.com/threads/T-019d2346-6e6f-75e0-a97f-cdb6e26859f7 Co-authored-by: Amp --- main.py | 9 +++++++++ nodes.py | 10 ++++++++++ server.py | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/main.py b/main.py index 058e8e2de..575ea9cd9 100644 --- a/main.py +++ b/main.py @@ -139,7 +139,16 @@ def execute_prestartup_script(): spec.loader.exec_module(module) return True except Exception as e: + import traceback logging.error(f"Failed to execute startup-script: {script_path} / {e}") + from nodes import NODE_STARTUP_ERRORS, get_module_name + node_module_name = get_module_name(os.path.dirname(script_path)) + NODE_STARTUP_ERRORS[node_module_name] = { + "module_path": os.path.dirname(script_path), + "error": str(e), + "traceback": traceback.format_exc(), + "phase": "prestartup", + } return False node_paths = folder_paths.get_folder_paths("custom_nodes") diff --git a/nodes.py b/nodes.py index 37ceac2fc..5430e4bc2 100644 --- a/nodes.py +++ b/nodes.py @@ -2181,6 +2181,9 @@ EXTENSION_WEB_DIRS = {} # Dictionary of successfully loaded module names and associated directories. LOADED_MODULE_DIRS = {} +# Dictionary of custom node startup errors, keyed by module name. +NODE_STARTUP_ERRORS: dict[str, dict] = {} + def get_module_name(module_path: str) -> str: """ @@ -2298,6 +2301,13 @@ async def load_custom_node(module_path: str, ignore=set(), module_parent="custom except Exception as e: logging.warning(traceback.format_exc()) logging.warning(f"Cannot import {module_path} module for custom nodes: {e}") + module_name = get_module_name(module_path) + NODE_STARTUP_ERRORS[module_name] = { + "module_path": module_path, + "error": str(e), + "traceback": traceback.format_exc(), + "phase": "import", + } return False async def init_external_custom_nodes(): diff --git a/server.py b/server.py index 173a28376..8bb60b01b 100644 --- a/server.py +++ b/server.py @@ -753,6 +753,10 @@ class PromptServer(): out[node_class] = node_info(node_class) return web.json_response(out) + @routes.get("/custom_node_startup_errors") + async def get_custom_node_startup_errors(request): + return web.json_response(nodes.NODE_STARTUP_ERRORS) + @routes.get("/api/jobs") async def get_jobs(request): """List all jobs with filtering, sorting, and pagination.