Bug fixes
Notes CLI traceback regression (issue #883)
The try/except around the Modal .remote(...) dispatch in
cli/attio/notes.py caught only (RuntimeError, TypeError, ValidationError).
The exceptions the deployed functions actually raise — AttioError subclasses
(a stale --email that matches no person, a partial update whose original
note could not be deleted) and the SDKError family from the Attio SDK, which
Modal re-raises unwrapped in the caller’s process — are none of those three,
so every routine, expected failure dumped a raw Python traceback instead of
the one-line Error: ... on stderr the CLI contract describes
(CLI contract). The narrowing landed in a repo-wide
mechanical BLE001 lint pass (cebf36b) that was treated as non-reviewable;
the pre-narrowing except Exception printed the clean line, as the sibling
gtm attio companies commands still do.
The handler now catches AttioError and SDKError alongside the original
three, with a deliberate carve-out: the AttioError subclasses that signal a
developer or deployment problem — ConfigurationError, ConnectivityError,
DeploymentMismatchError — re-raise so a developer keeps the traceback a fix
needs; masking them behind a one-line error is the same trap as masking
Modal’s own NotFoundError or AuthError. Programming bugs (AttributeError
and friends) and the Modal deserialize-fallback ExecutionError likewise stay
developer-visible. The routine-vs-config taxonomy lives in the adapter
(libs/attio/errors.py, is_routine_attio_error) and reaches the CLI through
the src.edge facade, so the closed orchestration boundary stays intact.Last modified on October 2, 2026