> This page is for CLI.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.deel.com/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.<status>`, 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