diff --git a/backend/app/flow/controller.py b/backend/app/flow/controller.py index 74410d9..aba7b51 100644 --- a/backend/app/flow/controller.py +++ b/backend/app/flow/controller.py @@ -351,7 +351,7 @@ class FlowController: except Exception as exc: logger.warning("Node '%s' failed to load: %s", node_id, exc) entry.status = NodeStatus.ERROR - entry.error = _short_traceback(exc) + entry.error = _short_error(exc) return entry # ------------------------------------------------------------------------- @@ -405,7 +405,21 @@ def _bound(specs: list[MessageSpec]) -> list[MessageSpec]: return [spec for spec in specs if spec.name] -def _short_traceback(exc: Exception) -> str: - """The last frames of a failure, which is what a node author needs.""" - lines = traceback.format_exception(type(exc), exc, exc.__traceback__) - return "".join(lines[-3:]).strip() +def _short_error(exc: Exception) -> str: + """One line a node author can act on: what broke, and where in their code. + + The frames in between belong to the loader rather than to the node, so only + the line in the node's own source is kept. The full traceback stays in the + server log. + """ + if isinstance(exc, SyntaxError): + # Its own message already names the compiled file, which is noise here. + return f"{type(exc).__name__}: {exc.msg} (line {exc.lineno})" + + frames = [ + frame + for frame in traceback.extract_tb(exc.__traceback__) + if frame.filename.startswith(" - + {problem || style.label} diff --git a/frontend/src/components/ui/tooltip.tsx b/frontend/src/components/ui/tooltip.tsx index 715bf76..9f8762e 100644 --- a/frontend/src/components/ui/tooltip.tsx +++ b/frontend/src/components/ui/tooltip.tsx @@ -34,7 +34,7 @@ function TooltipTrigger({ function TooltipContent({ className, - sideOffset = 0, + sideOffset = 4, children, ...props }: React.ComponentProps) { @@ -50,7 +50,6 @@ function TooltipContent({ {...props} > {children} - )