Skip to content

Resilience — retries, fallback, round-robin

Use withRetry, fallback and roundRobin to recover from provider failures. Each helper takes and returns a LanguageModel, so you can combine them.

The platform model (model: "nola") handles its own retries and routing. It cannot be wrapped in these helpers; configure its built-in retry instead.

nola.config.ts
import { exponential, fallback, openai, withRetry } from "@nola-lang/providers";
import { defineConfig } from "@nola-lang/runtime";
export default defineConfig({
model: fallback([
withRetry(openai({ model: "gpt-5-mini" }), exponential({ maxRetries: 3 })),
openai({ model: "gpt-5-nano" }),
]),
});

withRetry(provider, policy) retries a failed provider request, waiting between attempts according to one of these policies:

Policy Fields Defaults
constant({ maxRetries, delayMs? }) flat delay between attempts delayMs: 0
exponential({ maxRetries, delayMs?, multiplier?, maxDelayMs? }) delay × multiplier per attempt, capped delayMs: 200, multiplier: 2, maxDelayMs: 10_000
  • A provider error marked definitive, or an HTTP 4xx other than 408 or 429, fails immediately. Retrying an authentication error or a bad request would not help.
  • If the provider reports retryAfterMs, Nola waits at least that long, up to the policy’s maxDelayMs. A maxDelayMs of 0, as with constant() and no delay, ignores Retry-After.
  • If every attempt fails, Nola rethrows the last error.

fallback([a, b, c]) tries the providers in order and returns the first success. If every one fails, it throws a NolaProviderError listing each failure. An empty array is a config error (NOLA3003).

roundRobin([a, b, c]) starts with a different provider on each call, then tries the others in order if it fails. Use it to spread load across equivalent endpoints. An empty array produces NOLA3003.

You can nest these helpers. For example, fallback([withRetry(a, …), roundRobin([b, c])]) returns a model you can assign to the default or a named entry.

The platform model must be the bare model value or the model map’s default entry. Wrapping it in withRetry, fallback or roundRobin produces NOLA3003.

The platform handles routing and failover on the server. Its client also retries failed requests: by default, it makes up to two retries, starting with a 500 ms delay and doubling it up to 10 s. It honours Retry-After and stops on definitive errors.

Use nola.infer({ retry }) to change or disable these retries:

nola.config.ts
import { defineConfig, nola } from "@nola-lang/runtime";
export default defineConfig({
model: nola.infer({
retry: { maxRetries: 4, delayMs: 250 },
// retry: false, // disable entirely
}),
});

You can still wrap the platform model with record() and use replay() to serve the resulting ledger offline.

Nola can retry at three levels. Choose the level that matches the failure you need to handle:

Layer What is retried Configured by When to use
Built-in correction loop the model’s answer: when it fails schema validation, the runtime sends a correction turn and asks again nothing — automatic; observable through onValidationFailed / onRetry and the receipt’s attempts always on; you do not configure it
Provider combinator withRetry(provider, policy) (or nola.infer({ retry })) the provider request — timeouts, 5xx, 408/429, network faults; definitive errors are not retried nola.config.ts transient provider trouble
Intent method .withRetry(n) the whole ask — composition, provider call, parse, validation — n extra flat attempts, no backoff, no definitive-error check at the ask site repeat an entire step; the callee of a call intent must be safe to run again

See Intent methods for whole-ask retries and Error handling for the errors returned when retries fail.

Next: Ask options