Skip to main content

Error codes

Every failure carries a code. It is the part a script or an agent should match on: the message is written for a person and will be reworded; the code is a promise.

xec on hosts.web-1 "systemctl restart nginx" -o json
{
"error": true,
"code": "CONNECTION_FAILED",
"message": "…",
"type": "EnhancedConnectionError"
}

The error document goes to stderr, and stdout stays empty on failure, so a caller that redirects stdout to a file never finds half a diagnostic in it.

Why words and not numbers

XE0417 would need this page open in another window to mean anything. CONNECTION_FAILED does not. Codes are read far more often than they are looked up, and renaming the readable ones to numbers would break every matcher already written against them in exchange for nothing.

System error numbers — ENOENT, EACCES, ECONNREFUSED, ETIMEDOUT — are passed through unchanged rather than translated. They are already a vocabulary every operator and every language knows.

The codes

CodeMeaning
USER_ERRORThe command was asked to do something it cannot; the message is the whole story.
VALIDATION_ERRORAn option or argument was not of the shape the command accepts.
CONFIG_ERRORThe project configuration is missing, unreadable, or describes something impossible.
RESOURCE_NOT_FOUNDA named target, task or file does not exist.
COMMAND_FAILEDThe command ran on the target and exited non-zero.
TIMEOUT_ERRORThe command was still running when its time ran out.
MAX_BUFFER_EXCEEDEDThe command produced more output than the buffer allows; stream it instead.
OPERATION_FAILEDAn operation this tool performs itself — a copy, a transfer — did not complete.
CONNECTION_FAILEDThe target could not be reached, or refused the connection.
ADAPTER_ERRORThe adapter for this kind of target could not carry out the request.
DOCKER_ERRORDocker refused the operation, or the daemon is not reachable.
KUBERNETES_ERRORThe cluster refused the operation, or kubectl could not reach it.
NETWORK_ERRORA network operation failed for a reason the adapter could not classify.
CONTEXT_ERRORThe target names a cluster context or kubeconfig that does not exist.
TASK_ERRORA configured task failed, or is defined in a way that cannot run.
RECIPE_ERRORA recipe failed, or is defined in a way that cannot run.
MODULE_ERRORA script or module could not be loaded.
FILESYSTEM_ERRORA file operation failed for a reason with no more specific code.
SECRET_NOT_FOUNDNo secret is stored under that name.
GET_ERRORThe secret exists but could not be read from the store.
SET_ERRORThe secret could not be written to the store.
DELETE_ERRORThe secret could not be removed from the store.
LIST_ERRORThe store could not be enumerated.
DECRYPTION_FAILEDThe record was found but could not be decrypted; the passphrase or the machine differs.
STORAGE_ACCESS_ERRORThe secret store directory cannot be read or written.
GIT_OPERATION_FAILEDThe git secret provider could not complete a git operation.
TEAM_MEMBER_NOT_FOUNDNo team member is registered under that name.
UNKNOWN_ERRORThe failure was not recognised; the message and, with --verbose, the stack are all there is.

Exit codes

The code identifies what failed; the exit status says only whether something did. They are separate on purpose — a shell can act on one and a program on the other.

  • 0 — success
  • The command's own exit code, when exactly one target ran and exited non-zero, so xec on web-1 "test -f /etc/nginx.conf" works in an if
  • 2 — the arguments were not valid
  • 1 — everything else

Adding a code

A code is a promise, so the list is pinned: error-codes.test.ts fails if one is removed, if two codes describe the same idea, or if the source emits a code the catalogue does not describe. A code a caller can see is one they may match on.