Skip to content

feat(cli-v2): add --json global flag with structured error envelope#16042

Open
iamnamananand996 wants to merge 2 commits into
devin/1779374495-cli-v2-error-rendererfrom
devin/1779375213-cli-v2-json-error-envelope
Open

feat(cli-v2): add --json global flag with structured error envelope#16042
iamnamananand996 wants to merge 2 commits into
devin/1779374495-cli-v2-error-rendererfrom
devin/1779375213-cli-v2-json-error-envelope

Conversation

@iamnamananand996
Copy link
Copy Markdown
Contributor

Description

Linear ticket: Refs FER-10016

Wave-2 R13 of the cli-v2 error UX/DX cleanup: a --json global flag that renders failures as a structured JSON envelope on stderr, so CI pipelines and agents can parse error details without scraping human output.

Stacked on #16040 (wave-1 renderer + --debug). Re-target to main after #16040 merges.

Envelope shape

{
  "ok": false,
  "code": "AUTH_ERROR",
  "message": "You are not logged in.",
  "hint": "Run `fern auth login`.",
  "docsLink": "https://buildwithfern.com/learn/cli/auth",
  "violations": [
    { "severity": "error", "message": "...", "file": "fern.yml", "line": 7, "column": 13 }
  ],
  "logFile": "~/.fern/v1/logs/2026-05-20T18-58-00.log",
  "debug": { "stack": "...", "causes": ["..."] }
}
  • code is null for non-CliError failures (plain Error, unknown throwables).
  • violations is populated for ValidationError and SourcedValidationError; the latter includes file/line/column from the YAML source.
  • logFile is only set when there's something written to the per-run debug log.
  • debug only appears when --debug (or FERN_DEBUG=1) is also on.
  • TaskAbortSignal (Ctrl+C) still returns null — no envelope is emitted on clean shutdowns.

Changes Made

  • New ErrorEnvelope / ErrorEnvelopeViolation / ErrorEnvelopeDebug types and buildErrorEnvelope() in packages/cli/cli-v2/src/errors/renderError.ts. renderError(error, { json: true }) short-circuits to the JSON path.
  • packages/cli/cli-v2/src/context/GlobalArgs.ts: added json?: boolean.
  • packages/cli/cli-v2/src/cli.ts: registers --json as a global yargs option (commands that already declared a local --json for success output continue to work — yargs merges the definitions).
  • packages/cli/cli-v2/src/context/withContext.ts: threads args.json through to handleError, passes the log-file absolute path into the envelope, and suppresses the dim "Logs written to:" hint in JSON mode so the envelope is the only thing on stderr.
  • packages/cli/cli-v2/src/commands/_internal/yargsFailHandler.ts: yargs .fail runs before parsing finishes, so it inspects process.argv for --json/--no-json/--json=true and routes through the same renderer. Help block is suppressed in JSON mode.
  • Unreleased changelog entry: packages/cli/cli/changes/unreleased/cli-v2-json-error-envelope.yml (feat).

Testing

  • Unit tests added/updated — 13 new renderError --json mode cases covering TaskAbortSignal, CliError, ValidationError, SourcedValidationError, plain Error, non-Error throwables, logFile, debug=true, debug=false, and ANSI-free output. All 22 renderError.test.ts tests pass; the full cli-v2 suite (725 tests) is green.
  • Manual testing completed — pnpm format, pnpm lint:biome, pnpm check, pnpm turbo run compile --filter @fern-api/cli-v2 all clean.
  • Updated README.md generator (N/A — public CLI surface; will land alongside R15's user-facing errors README)

Link to Devin session: https://app.devin.ai/sessions/c00fe336eaa44387a47db9083451e93c
Requested by: @iamnamananand996

Adds a --json global flag that renders errors as a JSON envelope on stderr for CI pipelines and agents:

  {
    "ok": false,
    "code": "AUTH_ERROR",
    "message": "You are not logged in.",
    "hint": "Run `fern auth login`.",
    "docsLink": "https://buildwithfern.com/learn/cli/auth",
    "violations": [...],
    "logFile": "~/.fern/v1/logs/...",
    "debug": { "stack": "...", "causes": [...] }
  }

- Threads json through withContext.handleError + the shared yargs fail handler
- ValidationError and SourcedValidationError serialize each violation with file/line/column
- --debug --json adds stack and cause-chain info under debug.*
- logFile is embedded so CI/agents don't need to parse the dim hint line
- 13 new tests cover every branch (TaskAbortSignal, CliError, ValidationError,
  SourcedValidationError, generic Error, non-Error throwables, logFile,
  debug=true/false, ANSI-free output)
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@iamnamananand996 iamnamananand996 marked this pull request as ready for review May 21, 2026 15:10
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.

Import assertNever and change titleForCode to have no fallback, returning explicit titles for all known CliError codes (including a new INTERNAL_ERROR case). Replace previous fallback usages at call sites with the new titleForCode signature and use assertNever in the default branch to enforce exhaustiveness and improve type safety. Update error envelope building so default messages use titleForCode directly.
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