Skip to content
Agentside
Esc
↑↓navigate↵open⌘Jpreview
On this page

Error handling

Fallbacks, retries, timeouts and typed errors that keep a broken twin from reaching an agent.

A markdown twin is a second copy of your content, so it should never make a page worse for the agent reading it. Agentside picks the most useful answer it can still give whenever a source fails.

Fallbacks

What failed Negotiated request Explicit .md request
A variant source Control twin Control twin
No route matches HTML page from next() Markdown 404
The source returned null or the remote answered 404 HTML page from next() Markdown 404
The source threw, failed or timed out HTML page from next() Markdown 503 with Retry-After: 30

A negotiated request is one that Agentside answered with markdown because of the Accept header or the user agent. Those visitors asked for your page, so a broken twin falls back to the page instead of an error.

Retries

Remote sources retry network errors and 5xx responses with exponential backoff that starts at 100 milliseconds. Other 4xx responses fail immediately because retrying will not change them.

agentside({
  routes,
  retries: 3,
});

retries defaults to 2 and only applies to remote() sources. Set it to 0 to fail on the first error.

Timeouts

Every function and remote source is bounded by timeoutMs, which defaults to 5000. The timeout covers the whole load including retries and fails with SourceTimeout when it runs out.

agentside({
  routes,
  timeoutMs: 1500,
});

Remote requests are aborted when the timeout fires. Local functions cannot be cancelled, so their result is ignored instead.

Reporting

onError(error, path) receives one of the typed errors below. It runs for every failing variant, even when the variant only returned null, and for every failing control twin except a missing one.

agentside({
  routes,
  onError: (error, path) => logger.warn("agentside", { path, error }),
});

Typed errors

All errors are Effect tagged errors with a _tag you can switch on. They are exported from both @usenotra/agentside and @usenotra/agentside/effect.

Error Fields Raised when
NotFound path No route matches or the source returned null.
RenderFailed path, cause A local function threw or rejected.
RemoteFailed path, url, status?, cause? A remote request failed or returned a non-2xx status other than 404.
SourceTimeout path, timeoutMs A source took longer than timeoutMs.
import type { ServeError } from "@usenotra/agentside";

function describe(error: ServeError) {
  switch (error._tag) {
    case "RemoteFailed":
      return `upstream ${error.url} answered ${error.status ?? "nothing"}`;
    case "SourceTimeout":
      return `timed out after ${error.timeoutMs}ms`;
    default:
      return error._tag;
  }
}

Failures are never cached, so the next request tries the source again.

Was this page helpful?