Loopfour

Errors, retries and timeouts

Configure how a step behaves when it fails, how retries and timeouts work, and the shape of the error responses the Loopfour API returns.

This page covers two kinds of failure: a step that fails inside a run, and an API request that Loopfour refuses. The plain-language guide for people reviewing runs is Fix a failed run.

When a step fails

Each step can carry an errorHandling object:

{
  "id": "sync_customer",
  "type": "action",
  "name": "Update the CRM record",
  "action": "hubspot.updateContact",
  "config": { "...": "..." },
  "errorHandling": {
    "strategy": "continue",
    "fallback": { "synced": false }
  }
}
strategyWhat happens
fail (default)The step is recorded as failed, the run stops and its status becomes failed
continueThe step is recorded as failed and the run goes on to the next step. Later steps read a replacement output (below)
retryThe run engine does not retry the step. The run stops as with fail

With continue, the step's output becomes:

  • without a fallback: { "error": true, "message": "<error message>" };
  • with a fallback: the fallback fields, plus message and originalError set to the error message.

When the failing action names the records behind the failure, the output also has them in details, for example {{steps.sync_customer.details.<field>}}. An action keeps only short text, finite numbers and true/false values there, so a field can be missing.

A later Condition step can branch on it, for example { "left": "{{steps.sync_customer.error}}", "operator": "eq", "right": "true" }.

Rejected approvals

A rejected Approval step, or one that times out without approval, fails the step and stops the run. With strategy: "continue" the run goes on, and the step's output holds the decision plus error: true and a message.

Retries and timeouts per step

The step schema accepts retryConfig and timeoutMs, but the run engine does not apply them today, and a failed run is not retried on its own. Retries happen inside a block instead:

  • Some integration actions retry a provider call on their own when it answers 408, 429 or a 5xx status, or on certain network errors. By default only repeat-safe methods (GET, HEAD, PUT, DELETE) are retried, so a POST that creates a record is not sent twice. Whether an action does this is set per action.
  • The API Request block has its own retry and timeout settings.

To limit a whole run, set settings.maxDurationSeconds on the workflow (minimum 5). The run is stopped when the limit is reached. See Settings.

Step error codes

A failed step's entry in the run's stepResults has an error object with a code and message:

codeMeaning
STEP_ERRORThe step's action threw an error. details.errorClass and details.causeChain describe the underlying error
INPUT_VALIDATION_FAILEDThe resolved config did not match the step's inputSchema. details.validationErrors lists the problems
OUTPUT_VALIDATION_FAILEDThe step's output did not match its outputSchema

A run that cannot find a secret it references fails with the message Missing required secrets: <keys>.

Retry or restart a failed run

CallScopeWhat it does
POST /runs/:id/retryworkflows:executeStarts a new run for a failed or cancelled run, from the first failed step, or from the first step a cancelled run did not finish. Earlier results are reused
GET /run-observability/runs/:id/retry-previewruns:readShows which steps a retry or restart would run, with a planFingerprint
POST /runs/:id/restartworkflows:executeStarts a new run from fromStepId, optionally with overrideInput. Send the planFingerprint from the preview; if the plan has changed since, the API answers 409 with code RETRY_PLAN_CHANGED
POST /runs/:id/cancelworkflows:executeStops a run that is still going

Retry and restart answer 400 with code INVALID_STATE for a run that is still live. Branch on error.code, not on the HTTP status. The full request and response shapes are in the Runs API.

A retried step runs its action again. If the step created a record in another system before it failed, check that system before you retry, so you do not create the record twice.

API error responses

Most errors share one envelope:

{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Workflow not found",
    "requestId": "req_7f3a...",
    "details": { }
  }
}

details is present only on some errors. Quote requestId when you contact support.

StatusCommon codesWhen
400BAD_REQUEST, VALIDATION_ERROR, WORKFLOW_NOT_ACTIVE, INVALID_STATEThe request cannot be applied as sent. POST /workflows/:id/run answers WORKFLOW_NOT_ACTIVE for a workflow that is not active, and VALIDATION_ERROR with details.errors when the input fails the workflow's inputSchema
401UNAUTHORIZEDMissing, invalid or expired API key
403FORBIDDENThe key lacks a scope; the message names it
404NOT_FOUNDThe resource does not exist in your company
408SYNC_TIMEOUTA sync run did not finish in time and onTimeout was throw_error
409CONFLICT, RETRY_PLAN_CHANGEDThe resource changed under you, or a name is already used. Reload and try again
422UNPROCESSABLE_ENTITY and specific codesWell-formed but cannot be applied; retrying the same request will not help
429RATE_LIMITEDToo many requests. Wait for the seconds in Retry-After
500INTERNAL_ERROR, TRIGGER_ERRORSomething failed on Loopfour's side. TRIGGER_ERROR means the run was recorded but could not be queued
502UPSTREAM_ERRORA provider Loopfour called could not be reached
503SERVICE_UNAVAILABLEA dependency is down for a moment. Retry later

Request body validation

When a request body does not match an endpoint's schema, the 400 body lists each problem instead of a code:

{
  "success": false,
  "error": {
    "name": "ZodError",
    "issues": [
      { "path": ["steps"], "message": "Too small: expected array to have >=1 items" }
    ]
  }
}

Read issues[].path to find the field.

Inbound webhook routes

The /webhooks/... routes do not use the envelope. They answer with a short body such as { "error": "Invalid signature" } (401) or { "error": "Unknown provider: <name>" } (404). See Webhook trigger.

Retry your own requests safely

  • Retry 429, 502, 503 and network errors with a growing wait. On 429, wait at least Retry-After seconds.
  • Do not retry other 4xx responses unchanged; fix the request first.
  • Send an idempotencyKey with POST /workflows/:id/run. A repeat with the same key for the same workflow returns the existing run instead of starting a second one.

On this page