BoundaryML/baml · warning · BamlAbortError

Operation was aborted

Error message

Operation was aborted

What it means

A BamlAbortError with message 'Operation was aborted' is thrown by the stream's driveToCompletion when the AbortSignal passed to the streaming call has fired. The library checks the signal before consuming further FFI stream events and surfaces the abort as a typed error. It indicates the caller cancelled the operation, not a BAML/provider failure.

Source

Thrown at engine/language_client_typescript/typescript_src/stream.ts:36

    private finalCoerce: (result: any) => FinalOutputType,
    private ctxManager: RuntimeContextManager,
    abortSignal?: AbortSignal,
  ) {
    this.abortSignal = abortSignal;

    // Listen for abort to clean up
    if (abortSignal) {
      abortSignal.addEventListener("abort", () => {
        this.eventQueue.push(null); // Signal end of stream
      });
    }
  }

  private async driveToCompletion(): Promise<FunctionResult> {
    try {
      // Check for early abort
      if (this.abortSignal?.aborted) {
        throw new BamlAbortError(
          "Operation was aborted",
          this.abortSignal.reason,
        );
      }

      this.ffiStream.onEvent(
        (err: Error | null, data: FunctionResult | null) => {
          if (err) {
            this.error = err;
            return;
          }

          this.eventQueue.push(data);
        },
      );

      const retval = await this.ffiStream.done(this.ctxManager);

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Catch BamlAbortError separately and treat it as expected cancellation rather than a failure.
  2. Check that you did not abort the controller prematurely (e.g. setTimeout or request teardown firing early).
  3. If partial output is useful, consume stream events incrementally instead of only awaiting the final result.
  4. Remove or correctly scope the abortSignal if the stream should run to completion.

Example fix

// before
const result = await b.ExtractStory(streamOpts) // unhandled abort
// after
try {
  const result = await b.ExtractStory({ abortSignal: controller.signal })
} catch (e) {
  if (e instanceof BamlAbortError) return null // cancelled
  throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before streaming: if (controller.signal.aborted) return null // skip the call entirely

Try / catch

try {
  const result = await b.ExtractStory({ abortSignal: controller.signal })
} catch (e) {
  if (e instanceof BamlAbortError || e.name === 'BamlAbortError') {
    return null // expected cancellation
  }
  throw e
}

Prevention

When it happens

Trigger: Calling a b.stream.* function with an options.abortSignal whose .aborted becomes true (or was already true) while the result is being driven to completion.

Common situations: Request timeouts via AbortController.timeout(); user cancels in a UI; server request context (e.g. Next.js/Hono) aborts on client disconnect; stopping an agent loop early.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/9051b6c4cac6b973. Report an issue: GitHub.