> ## Documentation Index
> Fetch the complete documentation index at: https://docs.markpdf.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Error handling

> MarkpdfClientError, the error interceptor and retry strategy in Angular.

# Error handling

`MarkpdfService` propagates errors like standard Angular `HttpErrorResponse`, unless you log `markpdfErrorInterceptor` (see [Framework Guide](/docs/sdks/angular/framework-guide#error-interceptor)), in which case it normalizes them to `MarkpdfClientError`.

## Without interceptor: `HttpErrorResponse`

```ts theme={null}
this.markpdf.convertFile(file, { mode: "fast" }).subscribe({
  next: (markdown) => this.markdown.set(markdown as string),
  error: (err: HttpErrorResponse) => {
    console.error(err.status, err.error); // err.error es el body { error: string } de tu backend
  },
});
```

## With `markpdfErrorInterceptor`: `MarkpdfClientError`

```ts theme={null}
import { markpdfErrorInterceptor, MarkpdfClientError } from "@markpdf/angular";
import { provideHttpClient, withInterceptors } from "@angular/common/http";

provideHttpClient(withInterceptors([markpdfErrorInterceptor]));
```

```ts theme={null}
this.markpdf.convertFile(file, { mode: "fast" }).subscribe({
  next: (markdown) => this.markdown.set(markdown as string),
  error: (err: MarkpdfClientError) => {
    switch (err.kind) {
      case "rate-limit":
        this.showToast("Too many requests, retry in a few seconds.");
        break;
      case "payload-too-large":
        this.showToast("The file is too large.");
        break;
      case "vavalidation":
        this.showToast("Invalid file.");
        break;
      default:
        this.showToast("Could not convert the document.");
    }
  },
});
```

## `kind` table

| Status HTTP (from your backend) | `MarkpdfClientError.kind` | Typical cause                                          |
| ------------------------------: | ------------------------- | ------------------------------------------------------ |
|                           `400` | `"bad-request"`           | Invavalid or URL malformed body.                       |
|                   `401` / `403` | `"forbidden"`             | Configuration problem with your backend, not the user. |
|                           `413` | `"payload-too-large"`     | Document too large.                                    |
|                           `415` | `"unsupported-media"`     | Unsupported format.                                    |
|                           `422` | `"vavalidation"`          | Parameters are missing.                                |
|                           `429` | `"rate-limit"`            | Demasiadas peticiones.                                 |
|                           `5xx` | `"server-error"`          | Conversion error or your proxy backend.                |
|                     — (network) | `"network"`               | No connection, CORS, or backend down.                  |

```ts theme={null}
class MarkpdfClientError extends Error {
  kind: "bad-request" | "forbidden" | "payload-too-large" | "unsupported-media" |
        "vavalidation" | "rate-limit" | "server-error" | "network";
  statusCode: number | null;
  detail: string;
}
```

<Note>
  `"forbidden"` covers both `401` and `403` because, from the point of view of the end user of your Angular app, they both mean the same thing: your backend could not authenticate against API. User can't fix it — it's a configuration issue on your end.
</Note>

## Reintentos

`@markpdf/angular` does not automatically retry on its own — delegate that responsibility to the SDK you use in your backend (Node.js, Python, C++...), which does have configurable retries. See [Node.js SDK Error Handling](/docs/sdks/nodejs/error-handling#reintentos-automáticos) for the recommended server-side pattern.

If you need to retry from Angular itself (for example, a `429` call to your backend), use the standard RxJS operators:

```ts theme={null}
import { retry, timer } from "rxjs";

this.markpdf.convertFile(file, { mode: "fast" }).pipe(
  retry({
    count: 3,
    delay: (error, retryCount) => {
      if (error.status !== 429) throw error; // only retries 429
      return timer(2 ** retryCount * 1000);
    },
  })
).subscribe(/* ... */);
```

<Tip />
