> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hightouch.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Retry strategy

> When a destination rejects a record, Hightouch retries it automatically — during the run and on later runs — until it succeeds or you fix the underlying problem.

## How Hightouch retries records

Hightouch retries rejected records at two levels, both automatic.

**During a run.** When a destination rejects a record, Hightouch retries it within the same run using exponential backoff, up to a set number of attempts (five by default; some destinations set their own limit). Not every error is retried this way. A request the destination rejects as invalid — for example, a 400, 401, 403, or 422 response — is marked rejected immediately instead of retried. Rate-limited requests (429) get a larger retry budget.

**On later runs.** Hightouch keeps an index of every rejected record, keyed by its [primary key](https://docs.hightouch.com/models/creating-models.md#unique-primary-key-requirement). It retries each one on every subsequent run until the record succeeds or drops out of your model's query results. This layer has no attempt limit, so a record with a persistent problem retries indefinitely until you fix it.

### Example

Say you sync 10,000 records to Salesforce and five are locked in Salesforce when the run starts.

* If two unlock during the run, Hightouch's in-run retries update them before the run ends.
* Hightouch retries the remaining three on the next run. Once they unlock, they update. Hightouch keeps retrying rejected records until they succeed.

## Rejected rows don't mean a failed run

A run that finishes with rejected records **completes with errors** rather than failing. The run finished and synced the rows it could, but not every row landed. In the run list, this shows as **Completed with errors**, a warning-level status distinct from a failure. A run is marked **Failed** only when the whole run errors, such as a query failure, an authentication error, or a destination error that stops it before rows process.

So a completed run doesn't guarantee that every record synced. When you troubleshoot, check both the run status and the rejected-row count in the run's **Results** column or the [live debugger](https://docs.hightouch.com/syncs/debugger.md). Set up [alerting](https://docs.hightouch.com/syncs/alerting.md) to be notified when rows are rejected. The **Rejected rows** alert fires when a run rejects one or more rows.

## Split retries

Some destinations reject an entire batch when it contains even one invalid record. For those, you can enable **split retries**.

With split retries on, Hightouch splits a rejected batch in half and retries each half separately. If a half still fails, Hightouch splits it again, and repeats until the destination marks each record individually as successful or rejected. Splitting stops after a set number of rounds.

Split retries pinpoint which records are rejected and why, and they keep valid records from being re-sent alongside invalid ones. Records still rejected at the end of the process are retried on the next run.

To turn them on, set **Would you like to enable split retries?** to **Yes** in the sync configuration. To check whether a destination supports split retries, see its documentation.

> [!WARNING]
>
> Split retries can lengthen sync times, because a failing batch is retried in
> progressively smaller pieces.

## When to step in

Hightouch recovers from transient problems on its own. Step in when a record keeps failing for a reason retries can't resolve.

### A record keeps getting rejected

If a record holds data the destination won't accept — a malformed email, a value that breaks a destination rule — Hightouch retries it every run and it keeps getting rejected. Fix the data at the source: [edit your model](https://docs.hightouch.com/models/sql-editor.md) to correct the value or filter the row out of the query results. What counts as valid depends on the destination.

### Hightouch keeps retrying a removed row

If you set [delete behavior](https://docs.hightouch.com/syncs/overview.md#delete-behavior) to clear or delete removed records, Hightouch sends a clear or delete request when a row leaves your model's query results. If that request fails — the destination rejects it, or its API is unavailable — Hightouch retries it on the next run.

To stop retrying a removed row, choose one option:

* Set delete behavior to **Do nothing**. This applies to every removed row, not only the one being retried.
* Temporarily set delete behavior to **Do nothing**, run the sync [manually](https://docs.hightouch.com/syncs/schedule-sync-ui.md#manual-runs) once to clear the removed rows from the [CDC diff](https://docs.hightouch.com/syncs/cdc.md), then set delete behavior back.
* [Reset change data capture](https://docs.hightouch.com/syncs/resync-reset-clear.md#reset-cdc) without a backfill.

> [!WARNING]
>
> The last two options skip data. During the **Do nothing** run, Hightouch
> doesn't sync any rows CDC marks as removed. A reset-CDC run doesn't sync any
> model changes — added, changed, or removed rows — made since the previous run.
> To reduce the risk of missing changes, run a normal sync right before you use
> either option.

### A whole run failed

A **failed** run means the run errored as a whole, not that individual records were rejected. Open the run in the [live debugger](https://docs.hightouch.com/syncs/debugger.md) to see the error, then look it up in [error codes](https://docs.hightouch.com/developer-tools/error-codes.md) for the cause and fix.
