> ## Documentation Index
> Fetch the complete documentation index at: https://komga-sdk.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Result handling

> Handle generated result fields or opt into KomgaApiError with unwrap

Generated operations return a Promise whose default value has `{ data, error, request, response }`. API failures are returned in `error` rather than thrown. The SDK does not add a legacy error hierarchy, runtime validation errors, retries, or caching.

## Inspect a result

Check the discriminant before reading `data`:

```typescript theme={null}
import { getBookById } from 'komga-sdk';

const result = await getBookById(
  { bookId: 'book-123' },
  { client },
);

if (result.error === undefined) {
  console.log(result.data.metadata.title);
} else {
  console.error('Komga rejected the request', {
    status: result.response?.status,
    body: result.error,
  });
}
```

`request` and `response` are optional. A request can fail while it is being built or before Fetch produces a response, so do not assume either object exists. When a response exists, use the standard Fetch `Response` for status and headers; use the generated `error` payload for operation-specific fields.

Each operation has generated error and response types. For example, `getBookById` returns `GetBookByIdResponses` on success and `GetBookByIdErrors` for documented operation errors. Import those types when an application API needs to expose the generated contract rather than recreating it by hand.

## Distinguish failure stages

The same `error` field can represent different failure stages:

* **HTTP/API failure:** `response` exists and `response.ok` is false. The body is parsed as JSON when possible, otherwise text.
* **Network or Fetch failure:** `response` is usually undefined; inspect the thrown value supplied by the host Fetch implementation.
* **Request construction or serialization failure:** `request` may also be undefined.
* **Application validation failure:** not produced by the SDK; report the application-owned schema error separately.

Do not retry an unchanged `401` or `403`. For `429` and transient `5xx` responses, add an application-owned policy that respects server guidance and whether the operation is safe to repeat.

## Use `unwrap` as the throwing boundary

`unwrap` returns the generated data or throws `KomgaApiError` when `error` is present or the response is not successful:

```typescript theme={null}
import {
  getBookById,
  KomgaApiError,
  unwrap,
} from 'komga-sdk';

try {
  const book = unwrap(
    await getBookById({ bookId: 'book-123' }, { client }),
  );
  console.log(book.metadata.title);
} catch (error) {
  if (error instanceof KomgaApiError) {
    console.error('HTTP failure', error.status, error.body);
    console.error('Response available:', error.response !== undefined);
  } else {
    // Fetch-level failures and malformed invocation errors are not KomgaApiError.
    console.error('Request could not be completed', error);
  }
}
```

`KomgaApiError` exposes `body`, optional `status`, optional `request`, and optional `response`. Its message is a generic status message; inspect `body` for the generated API error payload. `unwrap` does not transform network errors into a second SDK hierarchy.

An `unwrap(undefined)` call throws a plain `Error` because no result was returned. Successful void operations return `undefined` through `unwrap`:

```typescript theme={null}
import { updateBookMetadata, unwrap } from 'komga-sdk';

const value = unwrap(
  await updateBookMetadata(
    { bookId: 'book-123', bookMetadataUpdateDto: { title: 'New title' } },
    { client },
  ),
);

// value is undefined after a successful 204 No Content response.
```

## Handle status codes in your application

The generated response gives you the standard Fetch `Response`, so status handling stays explicit:

```typescript theme={null}
import { getBookById } from 'komga-sdk';

async function getBookOrNull(bookId: string) {
  const result = await getBookById({ bookId }, { client });

  if (result.error === undefined) {
    return result.data;
  }

  if (result.response?.status === 404) {
    return null;
  }

  if (result.response?.status === 401) {
    throw new Error('Komga authentication is required');
  }

  throw new Error(`Komga request failed with status ${result.response?.status ?? 'unknown'}`);
}
```

For a throwing style, use `unwrap` and catch `KomgaApiError` at the boundary instead of recreating an SDK error hierarchy.

## Binary and text failures

The generated client can parse successful responses as JSON, text, blobs, array buffers, form data, or streams. An error response is still parsed as an API error/text body, so do not assume a failed media request has a `Blob` in `error`:

```typescript theme={null}
import { getBookPageByNumber } from 'komga-sdk';

const result = await getBookPageByNumber(
  { bookId: 'book-123', pageNumber: 1 },
  { client, parseAs: 'blob' },
);

if (result.error === undefined) {
  const url = URL.createObjectURL(result.data);
  // Revoke url after the browser no longer needs it.
}
```

For streams, consume the body only once. If an interceptor reads a response body before the generated parser, it must clone or replace the response deliberately.

## Add application policies explicitly

The core package uses native Fetch and has no default retries, response caching, timeout wrapper, or runtime validation. If your application needs those policies, compose them around generated operations or provide a custom `fetch` implementation through `createKomgaClient`. Keep policy errors in your application's error model.

```typescript theme={null}
const result = await getBookById(
  { bookId: 'book-123' },
  { client, signal: AbortSignal.timeout(10_000) },
);
```

Keep transport, validation, and application policy errors distinct. A single broad `catch` should preserve the original error and status rather than replacing every failure with an indistinguishable message.

## Next steps

> **[Direct API functions](/direct-api)**
>
> See the flat operation signatures.

> **[Runtime validation](/validation)**
>
> Add consumer-owned runtime schemas.

> **[Request customization](/interceptors)**
>
> Observe low-level request lifecycles.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.