Skip to content

Errors and cancellation ​

Handle stream failures at the consumer boundary and cancel work when its output is no longer needed.

1. Handle an agent failure once ​

An agent stream yields an error event with cumulative usage, then the iterator completes normally. The same failure rejects the stream.result promise, so funnel the awaited result through the same try/catch:

ts
const stream = agent.stream({ prompt: message })

try {
  for await (const event of stream) {
    if (event.type === 'error') {
      await logger.error('Agent stream failed', {
        error: event.error,
        usage: event.usage,
      })

      continue
    }

    await handleRuntimeEvent(event)
  }

  await stream.result
} catch (error) {
  await ui.fail('The request could not be completed.')
}

Usage includes completed turns and provider attempts that reported authoritative usage. It is empty when no authoritative usage was received.

2. Configure safe streaming retries ​

Pass retries with the stream run options:

ts
const stream = agent.stream({
    prompt: message,
    retries: {
        maxAttempts: 3,
        initialDelayMs: 100,
        maxDelayMs: 1000,
    }
})

Anvia retries a failed model invocation only before that invocation exposes provider progress. Once a delta or other non-error provider event is visible, retrying could duplicate output and is disabled.

3. Stop from React ​

useChat owns an AbortController. Connect its stop() method to the interface:

tsx
import { createHttpClientTransport } from '@anvia/client'
import { useChat } from '@anvia/react'

const transport = createHttpClientTransport({ endpoint: '/api/chat', format: 'jsonl' })
const chat = useChat({ transport })

return (
  <button
    type="button"
    disabled={chat.status !== 'streaming'}
    onClick={() => chat.stop()}
  >
    Stop
  </button>
)

Stopping aborts the active HTTP request and returns the hook to its ready state.

4. Stop from a custom browser client ​

ts
const controller = new AbortController()

const response = await fetch('/api/chat', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ type: 'messages', messages }),
  signal: controller.signal,
})

// Call this from the Stop button handler.
controller.abort()

Aborting fetch() cancels the response body even after headers have arrived.

For a normal createClientStreamResponse() response, cancellation calls return() on the event iterator. Closing an active AgentStream cancels its run. Server-side owners can also cancel the handle directly:

ts
const stream = agent.stream({ prompt: message })
stream.cancel('The caller no longer needs this run.')

Cancellation does not undo completed tool calls, writes, or external side effects. Long-running application work needs its own cancellation and cleanup design.

A resumable stream intentionally keeps draining and storing the original run after the response reader disconnects.

Built for Anvia.