Skip to content
pdcli
Get started

Exit codes

pdcli returns deterministic sysexits exit codes so scripts and agents can branch on the failure without parsing text. Every command shares the same ladder.

CodeMeaningPipedrive triggerWhat a script should do
0Success2xxContinue.
1Generic errorInspect the message; safe to surface and stop. audit --strict returns 1 on must-severity findings; a partial bulk/import failure returns 1 when some rows failed for non-data reasons.
64Usage / bad inputA bad invocation: an unknown flag or a missing/invalid argument (caught by the parser), or a value pdcli validated and rejected (invalid --period, unknown --checks name, several pipelines with no --pipeline, a CSV missing its name column, --ids over 100). Fix the invocation — retrying won't help.
65Data / validation400, 422The request body or input data was rejected: a bad field value, a non-numeric id cell in a CSV, an ambiguous upsert match, malformed --body JSON, or a conversion the API rejected. Fix the payload; don't retry unchanged.
69Service unavailable5xx, networkPipedrive is down/erroring, or the host is unreachable (DNS failure, connection refused, or a --timeout). pdcli already retried with backoff; safe to retry later.
70Internal CLI bugAn unexpected error inside pdcli — and nothing else (network, usage, and API failures all map elsewhere). File an issue; retrying won't help.
75Rate limited429Token budget exhausted. pdcli retries 429s with backoff; if they never clear it surfaces 75 (not 69), and --no-retry surfaces the first one. Back off and retry after the reset window.
77Auth / permission401, 403Token is invalid, expired, or lacks scope — including a failed OAuth refresh (invalid_grant). Re-authenticate (pdcli auth login). Don't loop. A 403 after repeated 429s is a rate-limit hard stop — wait for the reset, don't retry.
78Config / account402, missing domain/token, host-lock violation, no keychainThe CLI or account is misconfigured: no company domain, no keychain to write to, a pdcli api URL outside your host, a redirect off your host, or a 402 (plan lacks the feature). Fix config or the account — don't retry.
8Findings present (watch only)pdcli watch exits 8 when it surfaces new anomalies, so pdcli watch || notify fires only on findings. Not part of the general ladder — specific to watch.

The HTTP-status mapping lives in src/lib/errors.js (exitCodeForStatus): 400/422 → 65, 401/403 → 77, 402 → 78, 429 → 75, 5xx → 69. On top of that: an oclif parse error (unknown flag, missing/invalid argument) exits 64; an unreachable host or timeout exits 69; and only a genuinely unexpected throw exits 70.

The error format mirrors the success output format (the same --output / default_output / TTY rule). Whenever output is not an interactive table — an explicit --output json|yaml|csv, a non-table default_output in the profile, or stdout piped — the error is written to stderr as a single JSON object, so a machine consumer that gets JSON on success always gets a parseable failure. stdout stays clean so a successful-looking pipe can't swallow a failure:

{
"error": "ApiError",
"message": "Pipedrive API 422: Deal title must not be empty",
"exitCode": 65,
"statusCode": 422,
"path": "/api/v2/deals",
"errorInfo": "Please provide a valid title"
}

error is the error class name. statusCode, path, and errorInfo appear only for API errors (they're omitted for usage/config errors). Under --verbose the full Pipedrive body is added too. Only an interactive table context prints the message to stderr in human form; --verbose there adds the request path, status code, and error_info.

Terminal window
pdcli deal get 42 --output json > deal.json
case $? in
0) echo "ok" ;;
64) echo "bad invocation — fix flags/args" ; exit 1 ;;
65) echo "bad request — not retrying" ; exit 1 ;;
75|69) echo "transient — retry later" ; exit 1 ;;
77) echo "re-auth needed" ; pdcli auth status ; exit 1 ;;
78) echo "config/account problem" ; pdcli doctor ; exit 1 ;;
*) echo "failed with $?" ; exit 1 ;;
esac

pdcli also prints 127 (via the command-not-found hook) when you invoke a command name that doesn't exist.

See also: Troubleshooting for what to do per failure, and How pdcli talks to Pipedrive for the retry/backoff rules.

pdcli v0.18.0 · MIT · not affiliated with Pipedrive