Skip to content

fix(cli): emit structured JSON on auth failure when --json is set; enable --json on info#1248

Draft
DaveHanns wants to merge 1 commit into
masterfrom
cli-json-auth-error-envelope
Draft

fix(cli): emit structured JSON on auth failure when --json is set; enable --json on info#1248
DaveHanns wants to merge 1 commit into
masterfrom
cli-json-auth-error-envelope

Conversation

@DaveHanns

Copy link
Copy Markdown
Contributor

Summary

When apify commands are invoked with --json and hit an auth failure, they currently emit unstructured chalk-formatted prose to stderr and exit 1. Scripts that parse --json output see a broken pipeline. This PR teaches the top-level command handler to emit a machine-readable JSON envelope on stdout when --json was opted into, and also enables --json on apify info so scripts can read identity info in the same shape as apify actors info --json.

Draft — feedback welcome on the envelope shape ({ error: { type, message, exitCode } }) and on whether apify info --json should include anything beyond { username, userId }.

What changes

  • New AuthError class (src/lib/errors/AuthError.ts) — carries type: 'AuthError' and an exitCode (defaults to CommandExitCodes.MissingAuth). Extends Error so existing catch (err: Error) sites keep working.
  • getLoggedClientOrThrow now throws AuthError instead of a bare Error, preserving the existing process.exitCode = CommandExitCodes.MissingAuth behavior.
  • runCLI top-level catch (src/entrypoints/_shared.ts):
    • If the thrown error is an AuthError and the invocation opted into structured output (enableJsonFlag + --json in argv), emit {"error":{"type":"AuthError","message":"...","exitCode":N}} on stdout and exit with the AuthError's exit code.
    • Otherwise, keep the existing prose-on-stderr path, but exit with the AuthError's exit code rather than a hard-coded 1 — so callers can distinguish auth failures from other errors even without --json.
    • The --json check scans the raw argv slice rather than instance.flags.json, because errors can be thrown before the flags object is fully populated.
  • apify info gains --json (src/commands/info.ts) — emits { username, userId } when set. The API token is deliberately not included in --json output to avoid leaking secrets into script logs; use apify secrets or the auth file directly if you need the raw token.

Behavior of every other command is unchanged when --json isn't set.

Example

Before:

$ apify info --json
Error: Unknown option '--json'.

After (not logged in):

$ apify info --json
{
  "error": {
    "type": "AuthError",
    "message": "You are not logged in with your Apify account. Call \"apify login\" to fix that.",
    "exitCode": 1
  }
}
$ echo $?
1

After (logged in):

$ apify info --json
{
  "username": "acme-user",
  "userId": "abc123"
}

Test plan

  • apify info without --json still prints the human-readable "username: … / userId: …" output.
  • apify info --json on a logged-in machine prints { username, userId } and exits 0.
  • apify info --json on a logged-out machine prints the AuthError envelope on stdout (not stderr) and exits with the missing-auth code.
  • apify actors info <actorId> --json on a logged-out machine also emits the JSON envelope (regression check — this exercises the shared code path).
  • apify actors ls (no --json) on a logged-out machine still prints the existing prose message; no output shape change for non-JSON callers.
  • pnpm run lint and tsc --noEmit pass.

Notes

…able --json on info

Automation callers that invoke apify commands with --json currently get a
broken pipeline when they hit an auth failure: instead of a JSON payload on
stdout, they get chalk-formatted "Error: You are not logged in..." prose on
stderr and a generic exit 1. Scripts that pipe `apify ... --json | jq` blow
up on the prose.

This change introduces an `AuthError` class thrown by `getLoggedClientOrThrow`,
and teaches the top-level catch in `runCLI` to:

- emit a structured envelope `{"error":{"type":"AuthError","message":...,"exitCode":...}}`
  on stdout when the invocation opted into --json (via `enableJsonFlag` +
  `--json` in argv), and
- exit with the AuthError's own exit code (currently `CommandExitCodes.MissingAuth`)
  rather than the hard-coded 1, so callers can distinguish auth failures from
  other errors.

Also enables `--json` on `apify info` so scripts can read the logged-in
username / userId in the same structured shape used by `apify actors info --json`.
The token itself is never included in --json output to avoid leaking secrets
into script logs.

Ref: F14. See also #1223 for the broader exit-code taxonomy discussion.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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