Skip to navigation

Errors and exit codes

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:

CodeMeaning
0Success
1Any 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

{
"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:

FieldDescription
codeMachine-readable identifier of the failure. Either a CLI code from the table below or the error code returned by the API.
messageHuman-readable description. For API validation errors, one entry per invalid field, joined with ;.
nextSuggested next action, when the CLI can propose one.
request_idThe 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:

CodeCause
auth.missingNo token found in --token-stdin, DEEL_TOKEN, or the keychain
auth.invalidThe API rejected the token during auth login or auth status
auth.keychainNo keychain is available on this platform, or storing the token failed
auth.loginauth login received an empty token
usage.variantZero or more than one variant flag was passed
usage.path_param, usage.query_paramA required parameter flag is missing
usage.bodyThe operation requires --input, or a required body field is missing
usage.file--file is malformed or a required file part is missing
usage.max_itemsAn array body exceeds the operation’s maximum batch size
usage.jobjob status was called without a job id
usageThe argument parser rejected the command line
input.unrecognized--input is neither JSON, shorthand, file://, nor -
input.json--input is not valid JSON
input.shorthandA shorthand segment is not key=value
input.typeA field value cannot be coerced to the declared type
input.enumA field value is not one of the allowed values
input.stdinstdin could not be read for --input -
config.env--env or DEEL_ENV names an unknown environment
config.baseurlThe base URL is invalid or not HTTPS
network.insecureThe CLI refused to send credentials over a non-HTTPS URL
network.tlsCertificate verification failed; see private CAs
network.timeoutThe request exceeded the 30-second timeout
network.errorAny other transport failure
job.not_foundjob status was called with an unknown job id
job.errorA job lookup returned an error status
jq.errorThe --jq filter failed to compile or run
unexpectedAn unhandled internal error

API errors

When the API returns an error status after the 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.
{
"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.

Handle errors in scripts

Capture stderr and read code with jq:

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