VernLLMVernLLM
Core Features

Error Handling

LLMError types, what triggers each, and what gets retried

Failures from call() are surfaced as a normalized LLMError with a specific type. Check err.type to branch on what happened:

import { isLLMError } from 'vern-llm';

try {
  const result = await llm.call({ systemPrompt, userContent, schema });
} catch (err) {
  if (isLLMError(err)) {
    switch (err.type) {
      case 'validation':
        console.log(err.issues); // the schema's error object
        break;
      case 'api':
        console.log(err.status); // HTTP status, if the provider returned one
        break;
      case 'circuit_open':
        // provider is down, back off and do not retry immediately
        break;
    }
  }
  throw err;
}

Error types

timeout

A single attempt exceeded timeoutMs. Retried like any other transient failure.

api

The provider returned an HTTP error with a status code. Retried unless the status is in nonRetryableStatus (default 400, 401, 403).

parse

The response content was not valid JSON. Never retried because a malformed response will not fix itself on retry.

validation

JSON parsed successfully but failed schema.safeParse. Never retried for the same reason as parse. Carries .issues with the validator's error object.

circuit_open

The circuit breaker is open because the provider has failed too many times in a row. Fails immediately without hitting the provider.

aborted

The caller's AbortSignal fired. This represents intentional cancellation by the caller, not a timeout. See Cancellation.

unknown

Anything that does not fit the above categories, including network errors with no status code and unexpected provider responses. Retried by default.

What gets retried

shouldRetry skips a retry when any of these are true:

  • The signal has already aborted
  • error.type is 'parse' or 'validation' because these come from the response content rather than a transient fault, so retrying will not help
  • error.status is in nonRetryableStatus (default [400, 401, 403])

Everything else, including timeouts, 5xx errors, network failures, and unknown errors, is retried up to maxRetries with exponential backoff and jitter.

Exhausting all retries also records a circuit breaker failure if one is configured and throws the final normalized LLMError. The raw underlying error is not preserved on the thrown value beyond what extractStatus could pull from it.

On this page