Say what a node returned when it is not a dict of ports

Outputs are keyed by port, so a bare value cannot be one. The single mapping
point every caller routes through raised a bare AttributeError from
retval.items(); it now names the problem, and the message reaches the node the
way its other errors do.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7LwYgJfpkbLCTeiAf8U4A
This commit is contained in:
2026-08-16 16:44:06 +02:00
co-authored by Claude Fable 5
parent fa12ffd323
commit 0b2d8e587a
2 changed files with 28 additions and 1 deletions
+10 -1
View File
@@ -28,6 +28,10 @@ logger = logging.getLogger(__name__)
NodeResult: TypeAlias = "StateBackend | dict[str, Any] | None"
class NodeOutputError(TypeError):
"""A node function returned something that cannot be mapped onto ports."""
class Node:
"""
A pipeline node that wraps a function with typed inputs/outputs.
@@ -251,10 +255,15 @@ class Node:
kwargs[spec.port] = value
return kwargs
def _to_messages(self, retval: dict[str, Any] | None) -> dict[str, Any] | None:
def _to_messages(self, retval: Any) -> dict[str, Any] | None:
"""Map a function's port-keyed return value onto message names."""
if not retval:
return None
if not isinstance(retval, dict):
raise NodeOutputError(
f"'{self.local_id}' returned {type(retval).__name__}. Outputs are "
"keyed by port, so return a dict like {'out': value}, or None."
)
by_port = {s.port: s for s in self.output_ports if s.name}
outputs = {}
for key, value in retval.items():