Skip to content

chore(cli): migrate @fern-api/ir-generator to use CliError#15004

Merged
FedeZara merged 1 commit intomainfrom
FedeZara/refactor/cli-error-ir-generator
Apr 21, 2026
Merged

chore(cli): migrate @fern-api/ir-generator to use CliError#15004
FedeZara merged 1 commit intomainfrom
FedeZara/refactor/cli-error-ir-generator

Conversation

@FedeZara
Copy link
Copy Markdown
Contributor

@FedeZara FedeZara commented Apr 14, 2026

Description

Migrates @fern-api/ir-generator to use explicit CliError error codes on every failAndThrow / failWithoutThrowing call site.

This is one of the package migration PRs that follow the error classification system introduced in #14749.

Changes Made

Assigned typed error codes across call sites in packages/cli/generation/ir-generator/src/.

Error codes used

Code Usage
IR_CONVERSION_ERROR IR generation/conversion failures, type resolution errors
VALIDATION_ERROR Schema validation failures during IR generation
REFERENCE_ERROR Unresolvable type references, missing declarations
PARSE_ERROR Malformed input definitions

Files touched (grouped by area)

  • IR generation: Various files in ir-generator/src/ covering type declaration resolution, extended properties, and conversion utilities
  • Utils: getTypeDeclaration.ts, addExtendedPropertiesToIr.ts

Testing

  • Existing tests pass (pnpm test, excluding e2e and pre-existing environment failures)

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@FedeZara FedeZara changed the title refactor(cli): rename FernCliError to TaskAbortSignal chore(cli): migrate @fern-api/ir-generator to use CliError Apr 14, 2026
@FedeZara FedeZara force-pushed the FedeZara/refactor/cli-error-ir-generator branch from 5ca410e to 789fb94 Compare April 14, 2026 22:39
if (package_.service != null) {
throw new Error("Found duplicate service for " + serviceId);
throw new CliError({
message: "Found duplicate service for " + serviceId,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 User API definition metadata now silently exfiltrated to Sentry via InternalError/ResolutionError reclassification

Before this PR, these throws were plain Error objects. resolveErrorCode() in CliError.ts resolves unknown errors to Unclassified, for which shouldReportToSentry() returns false. After this PR they are CliError with InternalError or ResolutionError codes, both of which have shouldReportToSentry() = true. The full error (including its .message) is then sent to Sentry via captureException in the catch block inside runInteractiveTask.

Error messages that now reach Sentry include user-supplied API definition identifiers: serviceId, webhookGroupId, websocketChannelId, subpackageId (this file), plus JSON.stringify(endpointDeclaration) in convertTransport.ts and type/wire-key names in several other migrated files. The SENTRY_DSN is baked into the production CLI binary at publish time (see .github/workflows/publish-cli.yml), so this affects all users who have not set FERN_DISABLE_TELEMETRY=true.

Concrete impact: proprietary API definition names and structure are sent to Fern's Sentry instance whenever these error paths are hit, which was not the case before this PR.

Prompt To Fix With AI
For any CliError whose message embeds user-supplied values (serviceId, webhookGroupId, subpackageId, JSON.stringify(endpointDeclaration), wireKey, typeId, etc.) that is assigned an InternalError or ResolutionError code (both of which are Sentry-reportable), either:
1. Strip the dynamic user data from the message and move it to a separate Sentry 'extra' context field that is only attached at the captureException call site, OR
2. Change the code to ValidationError / ConfigError / ReferenceError for those specific call sites where the error is triggered by user configuration rather than a true programming bug (those codes are not Sentry-reported), OR
3. Add a Sentry beforeSend hook in SentryClient that scrubs or truncates error messages before transmission.

Files affected: PackageTreeGenerator.ts (serviceId, webhookGroupId, websocketChannelId, subpackageId), convertTransport.ts (JSON.stringify(endpointDeclaration), source.proto, relativeFilePath), convertExampleType.ts (discriminant, rawValueType, typeBeingExemplified), DynamicSnippetsConverter.ts (endpoint.id, typeId), validateObjectExample.ts (wireKey), validateTypeReferenceExample.ts, and others migrated in this PR.

Severity: low | Confidence: 78%

@FedeZara FedeZara force-pushed the FedeZara/refactor/cli-error-ir-generator branch 2 times, most recently from 0ec78fb to 0704cdc Compare April 17, 2026 10:40
@FedeZara FedeZara force-pushed the FedeZara/refactor/cli-error-ir-generator branch from 0704cdc to 4465a06 Compare April 17, 2026 18:04
@FedeZara FedeZara marked this pull request as ready for review April 18, 2026 14:29
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

Comment on lines +88 to +102
throw new CliError({
message: "Found duplicate webhook group for " + webhookGroupId,
code: CliError.Code.InternalError
});
}
package_.webhooks = webhookGroupId;
}

public addWebSocketChannel(websocketChannelId: WebSocketChannelId, fernFilepath: FernFilepath): void {
const package_ = this.getPackageForFernFilepath(fernFilepath);
if (package_.webhooks != null) {
throw new Error("Found duplicate webhook group for " + websocketChannelId);
throw new CliError({
message: "Found duplicate webhook group for " + websocketChannelId,
code: CliError.Code.InternalError
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The addWebSocketChannel method checks package_.webhooks instead of package_.websocket for duplicates, and the error message incorrectly says "webhook group" instead of "websocket channel". This will fail to detect duplicate websocket channels and may incorrectly throw an error when a webhook group exists.

// Should be:
if (package_.websocket != null) {
    throw new CliError({
        message: "Found duplicate websocket channel for " + websocketChannelId,
        code: CliError.Code.InternalError
    });
}

Note: This is a pre-existing bug in the original code (line 88-89), but the PR changes the error on lines 99-102 without fixing it.

Suggested change
throw new CliError({
message: "Found duplicate webhook group for " + webhookGroupId,
code: CliError.Code.InternalError
});
}
package_.webhooks = webhookGroupId;
}
public addWebSocketChannel(websocketChannelId: WebSocketChannelId, fernFilepath: FernFilepath): void {
const package_ = this.getPackageForFernFilepath(fernFilepath);
if (package_.webhooks != null) {
throw new Error("Found duplicate webhook group for " + websocketChannelId);
throw new CliError({
message: "Found duplicate webhook group for " + websocketChannelId,
code: CliError.Code.InternalError
});
throw new CliError({
message: "Found duplicate webhook group for " + webhookGroupId,
code: CliError.Code.InternalError
});
}
package_.webhooks = webhookGroupId;
}
public addWebSocketChannel(websocketChannelId: WebSocketChannelId, fernFilepath: FernFilepath): void {
const package_ = this.getPackageForFernFilepath(fernFilepath);
if (package_.websocket != null) {
throw new CliError({
message: "Found duplicate websocket channel for " + websocketChannelId,
code: CliError.Code.InternalError
});

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@github-actions
Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against latest nightly baseline on main (2026-04-18T04:46:15Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
csharp-sdk square 87s 139s 41s -46s (-52.9%)
go-sdk square 109s 146s 58s -51s (-46.8%)
java-sdk square 175s 193s 117s -58s (-33.1%)
php-sdk square 92s 119s 41s -51s (-55.4%)
python-sdk square 98s 155s 66s -32s (-32.7%)
ruby-sdk-v2 square 99s 157s 69s -30s (-30.3%)
rust-sdk square 97s 102s 48s -49s (-50.5%)
swift-sdk square 92s 134s 40s -52s (-56.5%)
ts-sdk square 105s 120s 50s -55s (-52.4%)

main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via fern generate). main (E2E): full customer-observable time including build/test scripts (nightly baseline, informational). Delta is computed against generator-only baseline.
⚠️ = generation exited with a non-zero exit code (timing may not reflect a successful run).
Baseline from nightly runs on main (latest: 2026-04-18T04:46:15Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-04-18 14:47 UTC

@github-actions
Copy link
Copy Markdown
Contributor

Docs Generation Benchmark Results

Comparing PR branch against latest nightly baseline on main (2026-04-18T04:46:15Z).

Fixture main PR Delta
docs 279.9s 271.3s (35 versions) -8.6s (-3.1%)

Docs generation runs fern generate --docs --preview end-to-end against the benchmark fixture with 35 API versions (each version: markdown processing + OpenAPI-to-IR + FDR upload).
Delta is computed against the nightly baseline on main.
Baseline from nightly run(s) on main (latest: 2026-04-18T04:46:15Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-04-18 14:49 UTC

@FedeZara FedeZara merged commit e0476cd into main Apr 21, 2026
598 of 603 checks passed
@FedeZara FedeZara deleted the FedeZara/refactor/cli-error-ir-generator branch April 21, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants