Skip to content

fix: type registry API failures and surface machine-readable error codes (BE-3271)#528

Open
mattmillerai wants to merge 2 commits into
mainfrom
matt/be-3271-registry-api-typed-errors
Open

fix: type registry API failures and surface machine-readable error codes (BE-3271)#528
mattmillerai wants to merge 2 commits into
mainfrom
matt/be-3271-registry-api-typed-errors

Conversation

@mattmillerai

@mattmillerai mattmillerai commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

ELI-5

When you comfy node publish or comfy node registry-install and the registry
says "no" (bad token, node not found, server error), the CLI used to blow up
with a raw Exception — a generic message or a Python traceback with no
machine-readable error code
. An agent driving the CLI couldn't tell what
went wrong programmatically.

This PR gives those failures a name and a code: the registry client now raises a
typed RegistryAPIError that carries the HTTP status and body, and the
publish/install commands turn that into the standard
renderer.error(code=..., details={status, body}) envelope — the same
structured-error contract the rest of the CLI already uses.

What changed

  • comfy_cli/registry/api.py — new RegistryAPIError(Exception) carrying
    optional status / body. The 5 bare raise Exception(...) (publisher-id
    / project-name validation, and the publish / list / install HTTP-failure
    branches) now raise RegistryAPIError. Any existing broad except Exception
    keeps working — RegistryAPIError subclasses Exception.
  • Hardening (55d620c) — response bodies are untrusted input, so
    sanitize_error_body() redacts the publish PAT (the publish request body
    carries it, and the registry can echo it back), escapes CR/LF so a body can't
    forge extra log lines, and bounds the body to 2000 chars. This means the
    message text is no longer byte-for-byte identical to the old
    raise Exception(...) for HTTP-failure branches — bodies may be redacted,
    escaped, or truncated. The two client-side validation messages are unchanged.
  • comfy_cli/command/custom_nodes/command.py — the publish and
    registry-install handlers gain a typed except RegistryAPIError (before the
    existing broad except) that emits renderer.error(code="node_publish_failed" | "node_install_failed", details={status, body}) and exits 1.
  • comfy_cli/error_codes.py — registers the two new codes with navigation
    hints (the registry test enforces every raised code is registered and every
    registered code carries a hint).
  • Teststest_api.py now asserts the typed exception + that status/body
    are carried (plus a client-side-validation case with status=None); new
    command-boundary tests assert publish/install surface the right code + details
    and exit 1.

Scope / judgment calls (this is the narrowed BE-3271, a DOWNGRADE from a

broader idiom sweep)

  • Deliberately scoped to publish/install boundaries, per the ticket wording.
    The list_all_nodes API call is converted to the typed exception (1 of the 5),
    but its hidden registry-list command boundary (display_all_nodes) is left
    untouched
    — it still catches RegistryAPIError as Exception, logs, shows
    the friendly message, and returns exit 0, exactly as before. Zero behavioral
    change there.
  • The wider typer.echo / ui.display_error_message migrations across
    custom_nodes/models were intentionally NOT done
    (the ticket explicitly defers
    those until those commands join the JSON-envelope contract).
  • One intentional behavioral change: on a registry API failure (non-2xx),
    registry-install now exits 1 instead of silently returning 0. This is
    a correctness fix — the sibling download-path test already documents the intent
    ("Must exit non-zero so automation / CI can detect the failure") — and it is
    narrowly scoped: only RegistryAPIError takes the new path; connection errors
    and everything else still hit the unchanged broad except (exit 0).
  • Fixed in passing (55d620c): the ui.display_error_message({str(e)})
    set-literal quirk in the publish broad-except fallback — it wrapped the
    message in a one-element set. Now passes str(e). One-character fix flagged
    in review; taken rather than deferred.
  • Deferred: making registry-install exit non-zero for non-RegistryAPIError
    failures (connection error, timeout, JSON decode) is tracked as
    BE-3294 / PR fix(registry): exit non-zero on non-RegistryAPIError registry-install failures #538.

Verification

  • ruff format --check: clean. ruff check: no errors in any file this PR touches.
  • This PR's own tests: 101 passed (tests/comfy_cli/registry/test_api.py +
    tests/comfy_cli/command/nodes/).

CI red is external to this PR (verified, not assumed)

Both go green on a rebase once those land.

…des (BE-3271)

Replace the 5 bare `raise Exception(...)` in comfy_cli/registry/api.py with a
typed RegistryAPIError carrying the HTTP status/body, and map it at the
publish/install command boundary to renderer.error(code=..., details={status,
body}) so node publish/install failures surface a machine-readable code instead
of a raw traceback or generic message. Messages are kept equivalent.
@mattmillerai mattmillerai added the agent-coded PR authored by the agent-work loop label Jul 17, 2026
@mattmillerai
mattmillerai marked this pull request as ready for review July 17, 2026 05:44
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jul 17, 2026
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 29 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7ff458d8-633c-4b9d-8360-78d831a1b8bb

📥 Commits

Reviewing files that changed from the base of the PR and between a732f5c and 55d620c.

📒 Files selected for processing (7)
  • comfy_cli/command/custom_nodes/command.py
  • comfy_cli/error_codes.py
  • comfy_cli/registry/__init__.py
  • comfy_cli/registry/api.py
  • tests/comfy_cli/command/nodes/test_node_install.py
  • tests/comfy_cli/command/nodes/test_publish.py
  • tests/comfy_cli/registry/test_api.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-3271-registry-api-typed-errors
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch matt/be-3271-registry-api-typed-errors

Comment @coderabbitai help to get the list of available commands.

@mattmillerai mattmillerai added the cursor-review Request Cursor bot review label Jul 17, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Cursor Review — Consolidated panel

Triggered by @mattmillerai.

Found 4 finding(s).

Severity Count
🟡 Medium 2
🟢 Low 1
⚪ Nit 1

Panel: 6/8 reviewers contributed findings.

Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)

Comment thread comfy_cli/command/custom_nodes/command.py
Comment thread comfy_cli/command/custom_nodes/command.py
Comment thread comfy_cli/command/custom_nodes/command.py
Comment thread comfy_cli/command/custom_nodes/command.py Outdated
…rors (BE-3271)

Addresses the cursor-review panel findings on the new
renderer.error(details={status, body}) surface:

- Add sanitize_error_body(): redacts known secrets, escapes CR/LF, and
  truncates to MAX_ERROR_BODY_CHARS before the untrusted registry
  response body reaches a log record or an error envelope.
- publish_node_version() passes the PAT as a secret, so a registry error
  that echoes the request payload back can no longer leak the token into
  terminal output or JSON logs.
- Apply the same bounding/escaping to list_all_nodes() and install_node(),
  which log the full str(e) — an attacker-controlled registry could
  otherwise forge log lines or flood CI logs.
- Fix the adjacent set-literal quirk in the publish fallback:
  display_error_message({str(e)}) rendered as {'...'} instead of a plain
  string.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Jul 17, 2026
@mattmillerai

Copy link
Copy Markdown
Collaborator Author

🤖 The reviews loop filed Linear follow-up ticket(s) for review thread(s) deferred as out of scope for this PR:

@mattmillerai

Copy link
Copy Markdown
Collaborator Author

🤖 Reviews-loop pass: no code changes needed — both red checks are external to this PR.

Review threads: all 4 Cursor findings were already addressed in 55d620c (PAT redaction + body bounding at the raise sites, and the {str(e)} set-literal nit). The one deferral is tracked as BE-3294 and is now PR #538. Nothing outstanding. CodeRabbit never reviewed — it is rate-limited, not blocking.

build (9 failures) — upstream dep regression, not this PR. This PR does not touch config_parser.py; the failures are ValueError: Comment cannot contain line breaks from tomlkit 0.15.1, released today 01:48 UTC, ~5h before the 07:08 run. Bisected locally:

  • tomlkit==0.15.1 → 8 failed in test_config_parser.py + test_node_init_strips_credentials (= all 9 CI failures)
  • tomlkit==0.13.3 (what uv.lock pins) → 81 passed

build resolves deps fresh instead of from the lock, so it picked up 0.15.1. Same red is on unrelated PRs #534/#535. Already being fixed by #533/#536 (config_parser) and #537 (install from uv.lock) — deliberately not duplicating that work here to avoid conflicting with those PRs.

test (Windows) — also external: ImportError: cannot import name __version__ from pydantic_core during dep install, via mixpanel. Covered by #529/#535.

This PR on its own is green: 101/101 tests in test_api.py + tests/comfy_cli/command/nodes/ pass, ruff format --check clean, and no ruff errors in any file this PR touches. It should go green on a rebase once the tomlkit fix lands on main.

@mattmillerai

Copy link
Copy Markdown
Collaborator Author

🤖 Reviews-loop re-check: no code changes needed — this PR is ready; both red checks are still external.

Independently re-verified rather than trusting the earlier pass:

Also refreshed the PR description, which had gone stale after 55d620c: it still claimed error messages were "byte-for-byte equivalent" (no longer true — bodies are now redacted/escaped/truncated, which reviewers should know) and listed the set-literal quirk as "left alone" when it was actually fixed.

Goes green on a rebase once the tomlkit fix lands on main. Not duplicating that work here to avoid conflicting with those PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-coded PR authored by the agent-work loop cursor-review Request Cursor bot review size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant