> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://developer.deel.com/cli/usage/errors/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.deel.com/_mcp/server. # Errors and exit codes > Interpret Deel CLI failures from the error envelope rather than the exit status The CLI reports failures in a single, stable shape. The exit status says only whether the command succeeded; the detail is in a JSON error envelope on stderr. ## Exit codes The exit status carries only two meanings: | Code | Meaning | | ---- | --------- | | `0` | Success | | `1` | Any error | The exit status is deliberately binary. Scripts should branch on the `code` field of the error envelope, not on numeric exit codes. ## The error envelope ```json { "error": { "code": "auth.missing", "message": "No API token found.", "next": "Run 'deel auth login', set DEEL_TOKEN, or pipe one with --token-stdin.", "request_id": "8b1c1a2e-3f96-4d05-a172-9e6b8c4d0f13" } } ``` Fields of the `error` object: | Field | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------- | | `code` | Machine-readable identifier of the failure. Either a CLI code from the table below or the error code returned by the API. | | `message` | Human-readable description. For API validation errors, one entry per invalid field, joined with `;`. | | `next` | Suggested next action, when the CLI can propose one. | | `request_id` | The `x-request-id` of the failed request, present for errors returned by the API. | The envelope is always written to stderr, so `stdout` stays empty on failure and pipelines do not receive partial output. ## CLI error codes These codes come from the CLI itself, distinct from codes the API returns: | Code | Cause | | --------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | `auth.missing` | No token found in `--token-stdin`, `DEEL_TOKEN`, or the keychain | | `auth.invalid` | The API rejected the token during `auth login` or `auth status` | | `auth.keychain` | No keychain is available on this platform, or storing the token failed | | `auth.login` | `auth login` received an empty token | | `usage.variant` | Zero or more than one variant flag was passed | | `usage.path_param`, `usage.query_param` | A required parameter flag is missing | | `usage.body` | The operation requires `--input`, or a required body field is missing | | `usage.file` | `--file` is malformed or a required file part is missing | | `usage.max_items` | An array body exceeds the operation's maximum batch size | | `usage.job` | `job status` was called without a job id | | `usage` | The argument parser rejected the command line | | `input.unrecognized` | `--input` is neither JSON, shorthand, `file://`, nor `-` | | `input.json` | `--input` is not valid JSON | | `input.shorthand` | A shorthand segment is not `key=value` | | `input.type` | A field value cannot be coerced to the declared type | | `input.enum` | A field value is not one of the allowed values | | `input.stdin` | stdin could not be read for `--input -` | | `config.env` | `--env` or `DEEL_ENV` names an unknown environment | | `config.baseurl` | The base URL is invalid or not HTTPS | | `network.insecure` | The CLI refused to send credentials over a non-HTTPS URL | | `network.tls` | Certificate verification failed; see [private CAs](/cli/usage/environments#corporate-networks-and-private-cas) | | `network.timeout` | The request exceeded the 30-second timeout | | `network.error` | Any other transport failure | | `job.not_found` | `job status` was called with an unknown job id | | `job.error` | A job lookup returned an error status | | `jq.error` | The `--jq` filter failed to compile or run | | `unexpected` | An unhandled internal error | ## API errors When the API returns an error status after the [retry policy](/cli/usage/idempotency-and-retries#retry-policy) is exhausted, the CLI maps the response into the same envelope: * `code` is the API's error code when the response includes one, otherwise `http.`, for example `http.403`. * For validation responses with an `errors` array, `message` lists each field and its problem, for example `amount: must be a positive number; date_submitted: is required`. * `request_id` is always present so that Deel support can locate the request. ```json { "error": { "code": "http.403", "message": "Request failed with status 403", "request_id": "8b1c1a2e-3f96-4d05-a172-9e6b8c4d0f13" } } ``` The Hypertext Transfer Protocol (HTTP) status codes and their meanings are documented in the [API reference](/api/reference). ## Handle errors in scripts Capture stderr and read `code` with jq: ```bash if ! OUT=$(deel adjustments create --invoice --input file://bonus.json 2>err.json); then CODE=$(jq -r '.error.code' err.json) case "$CODE" in auth.*) echo "authentication problem: $(jq -r '.error.next' err.json)" ;; input.*) echo "fix the request body: $(jq -r '.error.message' err.json)" ;; http.429) echo "rate limited after retries; try again later" ;; *) echo "failed with $CODE (request $(jq -r '.error.request_id' err.json))" ;; esac exit 1 fi ``` ## Next steps #### [Scripting and CI](/cli/guides/automation) Patterns for reliable automation with the CLI #### [Rate limits](/api/rate-limits) How the API applies rate limits and Retry-After > Build apps and integrations that extend and enhance the Deel services.