Skip to content

Platform

Errors

Halyard uses conventional HTTP status codes and returns a JSON error object with a stable type, a specific code and a request ID, so your code can decide what to do and support can find what happened.

On this page

Overview

2xx means success. 4xx means the request can't succeed as sent: fix it before retrying. 5xx means something went wrong on our side and the request is safe to retry. Branch on the error's type, which is stable, not on the human-readable message, which can change.

A request that fails
curl -i https://api.halyard.example/v3/jobs \  -H "Authorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3d" \  -H "Content-Type: application/json" \  -d '{ "task": "send-welcome-email", "payload": {} }' HTTP/2 400Halyard-Request-Id: req_4Tn8Wc2Ke7

The error object

Every error response has the same shape, wrapped in a top-level error key.

400 Bad Request
{  "error": {    "type": "invalid_request",    "code": "parameter_missing",    "message": "Missing required parameter: queue.",    "param": "queue",    "request_id": "req_4Tn8Wc2Ke7",    "doc_url": "https://docs.halyard.example/docs/errors#codes"  }}

Attributes

typestringrequired
The category of error, one of the error types below. Stable across API versions.
codestringrequired
A more specific reason, like parameter_missing or queue_paused. New codes can appear in minor releases, so always have a fallback.
messagestringrequired
A sentence for developers. Safe to log, not meant for end users.
paramstring
The request field the error is about, when there is one. Nested fields use dots: retry.max_attempts.
request_idstringrequired
The ID of this request, also sent in the Halyard-Request-Id header.
doc_urlstring
A link to the documentation for this error.
errorsarray
Only on validation_failed: one entry per failing field, each with a JSON Pointer path and a message.

HTTP status codes

HTTP status codes used by the API
StatusNameMeaning
200OKThe request succeeded.
201CreatedA job, event or other resource was created.
202AcceptedAccepted for asynchronous processing, like a batch create.
204No ContentSucceeded with nothing to return, like a delete.
400Bad RequestThe request is malformed or a parameter is invalid.
401UnauthorizedThe API key is missing or not valid.
403ForbiddenThe key isn't allowed to do this.
404Not FoundThe resource doesn't exist.
409ConflictState conflict or idempotency key reuse.
413Payload Too LargeThe body is over the size limit.
422UnprocessableValid JSON that fails a queue's schema.
429Too Many RequestsRate limited; see Retry-After.
5xxServer errorsOur fault. Safe to retry with the same idempotency key.

Error types

There are a small, fixed number of types. Handle the ones that matter to you and treat the rest by status code family.

Error types, what they mean and what to do
TypeStatusMeaningWhat to doRetry
invalid_request400A parameter is missing, has the wrong type or an invalid value.Fix the request. param names the field; don't retry unchanged.No
authentication_failed401No API key, a revoked key, or a test key used against live data.Check the Authorization header and the key's environment.No
permission_denied403The key is valid but its scopes don't allow this call, or the IP isn't allowlisted.Use a key with the needed scope or add the IP to the allowlist.No
not_found404The ID doesn't exist, was deleted, or belongs to another project.Check the ID and that the key belongs to the right project.No
conflict409The resource is in a state that doesn't allow this, like canceling a finished job.Fetch the resource, check its status, then decide.No
idempotency_mismatch409An idempotency key was reused with a different request body.Use a new key for a new request, or resend the original body.No
payload_too_large413The job payload or event data is over 256 KB.Store large data elsewhere and pass a reference, like a URL or an ID.No
validation_failed422The payload doesn't match the JSON Schema attached to the queue.Read errors[] for each failing path and fix the payload.No
rate_limited429Too many requests in a short window.Wait for Retry-After seconds, then retry with backoff.Yes
internal_error500Something went wrong on our side. We're paged automatically.Retry with backoff and the same idempotency key.Yes
service_unavailable503A region is shedding load or in maintenance.Retry with backoff. Check the status page if it persists.Yes

Validation errors

If a queue has a JSON Schema attached, payloads that don't match are rejected with validation_failed before the job is stored. The errors array lists every problem at once, so you can fix them in one pass.

422 Unprocessable Content
{  "error": {    "type": "validation_failed",    "code": "payload_schema_mismatch",    "message": "Payload does not match the schema for queue \"emails\".",    "request_id": "req_9Qa2Hd5Vn3",    "errors": [      { "path": "/user_id", "message": "is required" },      { "path": "/locale", "message": "must be one of: en, de" }    ]  }}

SDK exceptions

The official SDKs turn each error type into its own exception class, or a typed error value in Go. All of them expose type, code, param and the request ID.

Error types mapped to SDK exception classes
TypeNode.jsPythonGoRuby
invalid_requestInvalidRequestErrorInvalidRequestErrorErrInvalidRequestHalyard::InvalidRequestError
authentication_failedAuthenticationErrorAuthenticationErrorErrAuthenticationHalyard::AuthenticationError
permission_deniedPermissionDeniedErrorPermissionDeniedErrorErrPermissionDeniedHalyard::PermissionDeniedError
not_foundNotFoundErrorNotFoundErrorErrNotFoundHalyard::NotFoundError
conflict, idempotency_mismatchConflictErrorConflictErrorErrConflictHalyard::ConflictError
rate_limitedRateLimitErrorRateLimitErrorErrRateLimitedHalyard::RateLimitError
network failureAPIConnectionErrorAPIConnectionError*url.ErrorHalyard::ConnectionError
import { HalyardError, NotFoundError } from "@halyard/node"; try {  await halyard.jobs.cancel("job_3Rk9Tq7Xw2");} catch (err) {  if (err instanceof NotFoundError) return;          // already gone: fine  if (err instanceof HalyardError && err.type === "conflict") {    console.info("Job already finished");            // nothing to cancel    return;  }  throw err;}

Request IDs

Every response, successful or not, has a Halyard-Request-Id header like req_4Tn8Wc2Ke7. Log it next to your own errors. When you contact support, the request ID lets us find the exact request in seconds, including its timing and which region served it.

Request IDs are also listed in the dashboard under Logs, where you can search by ID for up to 30 days, and every job records the ID of the request that created it.

Retrying safely

Retry 429 and 5xx responses, and connection errors, with exponential backoff. Don't retry other 4xx responses unchanged: they will fail the same way.

Suggested