Skip to content

RegistryClient should expose structured HTTP errors #2505

Description

@bokelley

Summary

RegistryClient throws plain Error instances for non-2xx responses and encodes the HTTP status and response body into a formatted message:

throw new Error(`Registry request failed (${res.status}): ${this.preview(text)}`)

Consumers that need correct retry, rate-limit, or classification behavior must parse SDK error strings. This is brittle duplication across every production integration and can silently break if wording changes or the 200-character preview truncates the relevant JSON field.

Downstream example: https://github.com/scope3data/agentic-api/blob/main/apps/api/src/services/v2/property-list.service.ts

That integration currently maintains regex helpers for both:

  • Registry request failed (NNN) to recover the HTTP status; and
  • a JSON retryAfter field embedded in the error message to recover rate-limit timing.

Expected

Export a stable typed registry HTTP error, for example:

class RegistryRequestError extends Error {
  status: number
  method?: string
  retryAfterMs?: number
  details?: unknown
}

The exact shape is a maintainer choice. The important contract is that consumers can classify HTTP failures without parsing message. The human-readable message can remain unchanged for compatibility.

Acceptance criteria

  • All RegistryClient request methods throw the same exported typed error for non-2xx HTTP responses.
  • The HTTP status is available as a numeric field.
  • Rate-limit timing is exposed structurally when supplied through Retry-After and/or the registry's JSON error payload.
  • A bounded parsed error payload or stable details field is available when safe; callers do not need to regex the body preview.
  • Timeout/network errors remain distinguishable from HTTP response errors.
  • Existing human-readable messages remain useful and do not expose credentials or sensitive headers.
  • Tests cover at least 404, 429 with retry timing, 500, and an unreadable/non-JSON response body.

Why this belongs in the SDK

The SDK owns the HTTP transport and has the Response before reducing it to a string. Downstream callers cannot recover reliable structured data afterward, so a shared SDK error is the only place to eliminate string parsing consistently.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions