# Error Handling

Any call to the API can fail. When it does, the client raises an error instead of returning a result. Errors are organized in a hierarchy: a single base error for any client error, a more specific base for errors coming from the API, and then one error for each specific cause.

## Base errors

Every error raised by the client inherits from a single base class. Catching it lets you handle any client error in one place.

A more specific base class is used for errors returned by the API itself. It carries the HTTP status code and the raw response body, which is useful for logging.

<CodeTabs defaultValue="java">
<CodeTabs.Tab value="java" label="Java">
```java
try {
    Term result = client.intersection(List.of(a, b));
} catch (ApiException e) {
    System.out.println("API error " + e.getStatusCode() + ": " + e.getErrorCode());
} catch (RegexSolverException e) {
    System.out.println("Client error: " + e.getMessage());
}
```
</CodeTabs.Tab>

<CodeTabs.Tab value="javascript" label="JavaScript">
```javascript
try {
  const result = await client.intersection(a, b);
} catch (e) {
  if (e instanceof ApiError) {
    console.log(`API error ${e.statusCode}: ${e.body}`);
  } else if (e instanceof RegexSolverError) {
    console.log(`Client error: ${e.message}`);
  } else {
    throw e;
  }
}
```
</CodeTabs.Tab>

<CodeTabs.Tab value="python" label="Python">
```python
try:
    result = client.intersection(a, b)
except ApiError as e:
    print(f"API error {e.status_code}: {e.body}")
except RegexSolverError as e:
    print(f"Client error: {e}")
```
</CodeTabs.Tab>
</CodeTabs>

## Error reference

Each specific cause has its own error class, grouped below under the broader error it belongs to. Catching the broader one handles every cause listed with it, including causes added in future releases.

In Java, every class name ends with `Exception` (for example `RegexSyntaxException`). In the other SDKs it ends with `Error` (for example `RegexSyntaxError`). The names below are written without the suffix. Each one also corresponds to an `errorCode` in the API response body, spelled the same way, except `RegexSyntax` and `FairSyntax`, whose wire codes are `RegexSyntaxError` and `FairSyntaxError`.

### Bad request (400)

Raised when the request itself is rejected. `BadRequest` on its own means the request was malformed for a reason the more specific errors do not cover.

| Error | Cause |
| --- | --- |
| `RegexSyntax` | The provided regular expression has invalid syntax. |
| `FairSyntax` | The provided FAIR value is malformed or cannot be decoded. |
| `InvalidJson` | The request body could not be parsed. |
| `TooManyTerms` | The operation was called with more terms than your plan allows in a single request. Only occurs when [auto-batching](/advance-usage/auto-batching) is disabled. |
| `TooFewTerms` | The operation was called with fewer terms than it requires. Union, intersection, concatenation and difference each need at least two. |
| `InvalidNumberOfStringsToGenerate` | The requested `limit` of strings to generate is below the minimum or above the maximum allowed. |
| `AutomatonTooManyStates` | The automaton built to answer the request exceeds the maximum number of states allowed for your plan. |
| `TimeoutTooLarge` | The requested execution timeout is larger than the maximum allowed for your plan. |
| `TimeoutExceeded` | The operation did not finish within the requested or maximum allowed execution time. See [Heavy Operations](/advance-usage/heavy-operations). |

### Authentication and authorization (401, 403)

| Error | Cause |
| --- | --- |
| `Unauthorized` | Authentication failed, for a reason the more specific errors do not cover. |
| `MissingOrMalformedToken` | No API token was provided, or it is not in the expected format. |
| `InvalidToken` | The provided API token does not exist or is no longer valid. |
| `Forbidden` | The request was understood but is not allowed, for a reason the more specific errors do not cover. |
| `QuotaExceeded` | Your account's monthly request quota has been used up. See [Plans and Pricing](/plans-pricing). |

### Everything else (404, 429, 500)

| Error | Cause |
| --- | --- |
| `NotFound` | The requested endpoint or resource does not exist. |
| `TooManyRequests` | Your requests-per-second limit was exceeded and the client's automatic retries were exhausted. Does not surface in normal use; see [Rate limiting](#rate-limiting). |
| `InternalServer` | An unexpected failure happened on the RegexSolver servers. |

## Handling specific cases

A common pattern is to handle one or two specific errors, such as an invalid pattern or an exhausted quota, and treat everything else as a generic failure.

<CodeTabs defaultValue="java">
<CodeTabs.Tab value="java" label="Java">
```java
try {
    Term term = Term.regex(userProvidedPattern);
    Cardinality cardinality = client.getCardinality(term);
} catch (RegexSyntaxException e) {
    System.out.println("The pattern is not valid: " + e.getMessage());
} catch (QuotaExceededException e) {
    System.out.println("Monthly quota reached, try again later.");
}
```
</CodeTabs.Tab>

<CodeTabs.Tab value="javascript" label="JavaScript">
```javascript
try {
  const term = Term.regex(userProvidedPattern);
  const cardinality = await client.getCardinality(term);
} catch (e) {
  if (e instanceof RegexSyntaxError) {
    console.log(`The pattern is not valid: ${e.message}`);
  } else if (e instanceof QuotaExceededError) {
    console.log("Monthly quota reached, try again later.");
  } else {
    throw e;
  }
}
```
</CodeTabs.Tab>

<CodeTabs.Tab value="python" label="Python">
```python
try:
    term = Term.regex(user_provided_pattern)
    cardinality = client.get_cardinality(term)
except RegexSyntaxError as e:
    print(f"The pattern is not valid: {e}")
except QuotaExceededError:
    print("Monthly quota reached, try again later.")
```
</CodeTabs.Tab>
</CodeTabs>

## Rate limiting

The client tracks your requests-per-second limit locally and, when the API still answers with a rate-limit response, transparently waits the server-indicated delay and retries, spreading concurrent retries so they do not collide. Rate-limit errors are never raised in normal operation, even when many requests are sent at the same time; the `TooManyRequests` error only surfaces after several minutes of unsuccessful retries. To get the most accurate rate limiting, follow the recommendation in [Best Practices](/best-practices) to use a single client per API token.

## Oversized term lists

Your plan caps how many terms a single request may carry. With auto-batching enabled (the default), the client splits oversized `union`, `intersection` and `concat` calls into several requests and combines the results, so `TooManyTerms` is never raised. It only appears once you disable auto-batching. See [Auto-Batching](/advance-usage/auto-batching).
