Rendex
Recipe

Self-Healing Renders in Make — Retry, Then Fall Back

At volume, a render will occasionally hit a rate limit or a slow page. Instead of letting that fail the whole run, attach a Make error handler: a Break directive retries the transient case, and a Resume branch supplies a placeholder for the permanent one — so the scenario keeps going either way.

Last updated 2026-07-21

The Problem

One flaky render shouldn't take down a scenario. When you render at volume, some calls will hit a momentary rate limit (429), a transient 5xx, or a page that loaded slowly — the kind of failure that would have succeeded on a second try. By default Make treats a module error as fatal: the whole run stops, the bundle dead-letters, and either everything after the render is skipped or the operator has to replay by hand. And the opposite failure — a permanent 400 or 401 that will never succeed — shouldn't be retried at all; retrying it just wastes runs. A robust scenario has to tell the two apart.

The Solution

Make's error handlers do exactly this, and they're more expressive than a flat auto-replay. Attach an error route to the Rendex HTTP module and put a Break directive on it: on a transient error, Break retries the module a set number of times on an interval (with the run parked in between), which clears most 429s and slow-page timeouts on the second or third attempt. If it still fails — or the error is a permanent one like a 400 'one source' or a 401 — a Resume directive lets you hand downstream a fallback (a placeholder image URL, or a flag that routes the record to a review queue) so the rest of the scenario runs instead of dying. Because the handler can branch on the HTTP status, transient failures heal themselves and permanent ones degrade gracefully rather than looping.

How the Workflow Runs

Rendex HTTP module

POST /v1/screenshot renders the artifact — the module that gets an error handler attached.

Break — retry transient

On a 429 or 5xx, a Break directive retries the module a few times on an interval before giving up.

Resume — fall back

If it still fails (or a 4xx that won't heal), Resume hands downstream a placeholder image/flag instead of stopping.

Downstream always runs

The rest of the scenario continues with either the real render or the fallback — no dead-lettered run.

Input → Rendered Output

Left: a Make scenario — a Rendex HTTP module with a dashed error-handler route beneath it holding a Break directive labelled 'retry 3× / 15s' and a Resume branch labelled 'fallback placeholder'. Right: a timeline showing attempt 1 hit a 429, attempt 2 succeeded, and the real render flowing downstream.

Rendered by Rendex

What You Need

  • A Rendex API key — the free tier includes 100 renders/month with no card required.
  • A Make account on any plan (error handlers and directives ship on every Make plan).
  • The Rendex HTTP module already working (start from the Render HTML to a PNG recipe if not).
  • Optionally, a fallback value — a stock placeholder image URL or a Data store to flag failed records.

What This Recipe Uses

Break retries the transient case

Attach a Break directive to the module's error route to retry on a 429 or 5xx a few times on an interval — most rate-limit and slow-page blips clear on the second attempt.

Resume degrades gracefully

On a still-failing or permanent error, Resume hands downstream a fallback (placeholder URL or a review flag) so the rest of the scenario runs instead of dead-lettering.

Branch on the HTTP status

The handler can inspect the error code, so transient statuses retry and permanent ones (400 'one source', 401) route to fallback instead of looping uselessly.

Honor Retry-After on 429

Rendex returns a Retry-After on rate limits; use it as the Break interval so retries back off exactly as long as the API asks, rather than hammering it.

Build It

make-error-handler-setup.txt
# In Make: right-click the Rendex HTTP module -> "Add error handler".
# A dashed route appears under the module. Build it as:

Rendex HTTP module
  └─ (error route)
       1. Router (optional) — branch on the status code:
            Route "transient"  filter: {{ code }} in 429, 500, 502, 503
               -> Break     (retries below)
            Route "permanent" filter: {{ code }} in 400, 401, 403
               -> Resume    (fallback value below)

# Break directive settings:
#   Number of attempts : 3
#   Interval           : 15  (seconds; or the Retry-After value on 429)
#
# Resume directive:
#   Output -> a fallback, e.g. { "url": "https://cdn.example.com/placeholder.png" }
#   so downstream modules read {{ url }} and keep running.
body-render.json
// POST https://api.rendex.dev/v1/screenshot — a normal single-source render.
// The error handler wraps THIS module; the body doesn't change.
{
  "html": "<div style='padding:56px;font-family:system-ui'><h1>{{title}}</h1></div>",
  "data": { "title": "{{1.title}}" },
  "format": "png"
}
retry-matrix.txt
RETRY (Break) — transient, a second attempt usually works:
  429  Too Many Requests   -> back off by Retry-After, then retry
  500 / 502 / 503          -> brief blip, retry a few times
  (timeout on a slow page) -> retry, optionally raise the wait strategy

FALL BACK (Resume) — permanent, retrying can't help:
  400  VALIDATION_ERROR    -> e.g. two source fields; fix the body, don't loop
  401  INVALID_KEY         -> bad/rotated key; alert, don't retry
  403  FORBIDDEN / plan    -> feature not on this plan; route to review

# Retrying a 400/401 just burns runs — always branch on the code first.
inspect-429.sh
# On a rate limit Rendex returns 429 with a Retry-After header (seconds).
# Use that number as your Break interval. Inspect it with -i:
curl -i -X POST https://api.rendex.dev/v1/screenshot \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "html": "<h1>hi</h1>", "format": "png" }'
# ... HTTP/1.1 429 Too Many Requests
# ... Retry-After: 12          <- set Break interval to this

100 free API calls/month — no credit card required. Get your API key and start building.

Reach for this on any render that runs at volume or feeds something that can't just stop — batch invoice PDFs, per-record OG images, scheduled reports. The insight is that render failures come in two flavors and deserve opposite treatment: transient (429 rate-limit, a 5xx, a slow page that timed out) should retry, because a second attempt usually works; permanent (a 400 for sending two source fields, a 401 for a bad key) should not, because retrying can't fix a malformed request. Make expresses both through error-handling directives attached to the module. Break is the retry: set attempts and an interval so a 429 clears on backoff — and honor Rendex's Retry-After header value as your interval when you can. Resume is the graceful degrade: on a still-failing or clearly-permanent error, continue the flow with a fallback value (a stock placeholder render-link URL, or a Data-store flag) so downstream modules aren't starved. Ignore and Commit/Rollback exist for the cases where you'd rather drop the single bundle or unwind a transaction. The point is that the render step becomes self-healing: the common transient blip is retried away, the rare permanent error is caught and routed, and the scenario as a whole stops being one bad render away from a dead-lettered run. It's free-tier on the render side; the resilience is pure Make flow control, and it's the kind of ops-grade pattern that reads as 'built in Make', not ported from a channel that only offers a blanket replay.

Frequently Asked Questions

Related Resources