Skip to content

refactor: simplify error handling and reporting#226

Merged
angeloashmore merged 19 commits into
mainfrom
aa/error-handling
Jul 16, 2026
Merged

refactor: simplify error handling and reporting#226
angeloashmore merged 19 commits into
mainfrom
aa/error-handling

Conversation

@angeloashmore

@angeloashmore angeloashmore commented Jul 15, 2026

Copy link
Copy Markdown
Member

Resolves:

Description

Reworks how the CLI turns a failure into what the user sees, what we track, and what we report. Previously the entrypoint caught every error in one long chain of instanceof branches that each repeated the same tracking boilerplate and only differed in the message printed. That kept message wording far from the code that raised the error and blurred the line between telemetry and crash reporting.

The intent behind the changes:

  • Messages live on the errors. Each known error owns its user-facing message, so the top-level handler just prints it. A single lookup decides whether an error is known or unexpected.
  • Reporting is split by purpose. Telemetry records the failure of every command, including its message. Crash reporting is limited to unexpected errors plus the few known API and Type Builder failures we still want eyes on. Each failure reports once.
  • Observability is opt-in by flag. Telemetry and crash reporting sit behind explicit environment flags instead of implicit production checks, so their behavior is predictable everywhere.
  • Crash reporting drops the Sentry SDK. We only used a small slice of it, so it now builds and sends the envelope directly and the dependency is gone.
  • Clearer failure copy. Not-found messages name the missing resource, config errors point at prismic init, Type Builder errors link to the repository's settings, and secret token values are no longer echoed back. The sync watch loop surfaces the same contextual messages as one-off commands.

Command routing also moves out of the entrypoint into its own module, leaving the entrypoint focused on setup and failure handling.

No change to which commands succeed or fail; only to what users see and what we report when they do.

Checklist

  • A comprehensive Linear ticket, providing sufficient context and details to facilitate the review of the PR, is linked to the PR.
  • If my changes require tests, I added them.
  • If my changes affect backward compatibility, it has been discussed.
  • If my changes require an update to the CONTRIBUTING.md guide, I updated it.

Preview

How to QA 1


Note

Medium Risk
Touches all command exit paths, Sentry reporting, and telemetry gating; behavior changes for which errors are reported and what users see, though success/failure semantics are intended to stay the same.

Overview
Centralizes CLI failure handling by moving the command router to src/commands/index.ts and replacing the entrypoint’s long instanceof chain with getErrorMessage, a KNOWN_ERRORS list, and user-facing copy on the error types themselves.

Splits observability: Segment telemetry is controlled via PRISMIC_TELEMETRY_ENABLED (and exported isTelemetryEnabled); Sentry only initializes when PRISMIC_SENTRY_ENABLED is set or telemetry is on in production. Crash reports go to Sentry for unexpected bugs and a small set of known API/Type Builder failures; command end events still record failures with the resolved message.

Replaces @sentry/node-core with a minimal Sentry envelope fetch in lib/sentry.ts, removing OpenTelemetry-related lockfile entries.

Improves messages across API clients (resource IDs in not-found text, operation-specific unknownErrorMessage), config/Type Builder (prismic init hints, settings URL), model errors, InvalidEnvironmentError, and the sync watch loop (same auth/API context as other commands). Invalid CLI args from parseArgs surface as CommandError.

Reviewed by Cursor Bugbot for commit f1d6e19. Bugbot is set up for automated code reviews on this repo. Configure here.

Footnotes

  1. Please use these labels when submitting a review:
    ❓ #ask: Ask a question.
    💡 #idea: Suggest an idea.
    ⚠️ #issue: Strongly suggest a change.
    🎉 #nice: Share a compliment.

angeloashmore and others added 10 commits July 15, 2026 01:30
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Read response bodies once, add explicit json/body request options, and
move not-found messaging into request(). Standardize every client on
bare-base get*ServiceUrl builders and *ServiceRequest transport helpers,
with repository scoping handled in the helpers. Remove the unused
amplitude client and pass-through request helpers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an endpoint-level `unknownErrorMessage` request option so client
functions declare their failure message once, instead of each command
wrapping calls in a try/catch that converts `UnknownRequestError` into a
`CommandError`. Removes 35 duplicated try/catch blocks across 26 command
files.

The message now lives on the endpoint, so it applies to every caller
(including previously bare calls to shared endpoints like getProfile and
the preview endpoints). The server response body is no longer appended.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
getToken() and getHost() were never called apart — 34 command, adapter,
and index.ts sites called them as a pair — and each independently read
credentials.json, so every command read the file from disk twice.

Replace both with one getCredentials() that reads the file once and
applies the same env-var precedence and default-host fallback. Call sites
collapse from two awaited lines to one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Drop the unused issues field and custom constructors from the config
  Invalid* error classes; nothing ever read them, so the read functions'
  catch blocks lose their ZodError branching.
- updateRoute delegates straight to addRoute/removeRoute (the page branch
  duplicated the read and hasRoute check addRoute already does).
- checkIsTypeScriptProject returns exists() directly.
- Unexport symbols only referenced inside the module (findConfigPath,
  findSuggestedConfigPath, findLegacySliceMachineConfigPath,
  MissingLegacySliceMachineConfigError, the Route type).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
removeLocale inherited the client-level "Repository not found" default,
so removing a non-existent locale reported the repository as missing.
Override with "Locale not found: <code>", matching the resource-specific
messages getCustomType/getSlice already use.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
deleteSlice/deleteCustomType already look up the resource by id and
throw the same not-found error, so the explicit get before delete did
no extra work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Field add, edit, and reorder now surface duplicate and missing-field
errors using the full dotted path the user passed instead of only the
leaf segment.

Update and remove requests for a specific type or slice now report a
model-not-found message on 404 instead of the generic repository-not-
found message.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapse the 17-branch `catch` dispatcher in `src/index.ts` into a single
flow: a pure `formatError` maps a known error to its user-facing message,
tracking fires once, and only unknown errors reach Sentry. Segment now
records the error message on every failed command.

Reword the Type Builder requirement message and link to the repository's
settings page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@angeloashmore
angeloashmore marked this pull request as ready for review July 15, 2026 01:50
Comment thread src/index.ts
Comment thread src/lib/sentry.ts
Comment thread src/lib/sentry.ts
Comment thread src/index.ts Outdated
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread src/index.ts Outdated
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread src/index.ts
angeloashmore and others added 2 commits July 15, 2026 19:17
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move user-facing copy into the error classes themselves so index.ts
reads error.message instead of formatting each type in the catch block.
Extract the command router into src/commands, wrap parseArgs failures
as CommandError, and gate telemetry/Sentry via explicit env flags.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread src/index.ts
Comment thread src/index.ts
Comment thread src/index.ts
Comment thread src/lib/request.ts
angeloashmore and others added 2 commits July 16, 2026 03:02
Name the missing resource in preview, webhook, and OAuth token 404
messages, matching the existing type/slice messages. Drop the write
token value from its message since it is a secret.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move getErrorMessage from index.ts to a new src/error.ts and reuse it
in the sync watch loop. The poll-loop catch read error.message directly,
so an expired token mid-watch logged a blank line; it now shows the same
contextual message as the global handler.

Also drop the redundant unknownErrorMessage on deleteScreenshots (it
duplicated the push warning's prefix) and guard that warning against an
empty message.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cursor cursor 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 Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6c5a504. Configure here.

Comment thread src/lib/prismic/clients/wroom.ts
Comment thread src/commands/sync.ts
The watch loop threw a plain Error when it hit too many consecutive
failures, so the top-level handler treated the stop as an unexpected bug:
it printed the generic "CLI reached a bug" line and reported to Sentry
instead of showing the stop reason. Throw a CommandError so the message
reaches the user and the stop is not reported.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Base automatically changed from aa/refactor to main July 16, 2026 04:49
# Conflicts:
#	src/commands/sync.ts
#	src/index.ts
#	src/lib/prismic/clients/core.ts
#	src/lib/prismic/clients/custom-types.ts
#	src/lib/prismic/clients/wroom.ts
#	src/lib/prismic/models.ts
#	src/lib/request.ts
#	src/project.ts

@lihbr lihbr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

*chef kiss* LGTM

@angeloashmore
angeloashmore merged commit e98b481 into main Jul 16, 2026
26 of 29 checks passed
@angeloashmore
angeloashmore deleted the aa/error-handling branch July 16, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants