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

# Errors and diagnostics

> Facial Antispoofing status codes, how to tell a capture problem from a code problem, what to retry, and what to include in a support ticket.

## Status codes

| Code | What it means | Whose problem it is | Retry? |
| - | - | - | - |
| `200` | Analysis completed. Read `spoofing` for the verdict. | — | No |
| `400` | The image fails a hard requirement. | Yours | No |
| `401` | Api-key missing, invalid, or from another environment. | Yours | No |
| `422` + `No Face Detected` | No face was found in the image. | The capture's | No |
| `422` + `Bad request` and `detail[]` | The request body does not validate. | Yours | No |
| `499` | The client closed the connection. | Your network or timeout | Yes |
| `500` | Service-side error. | Depends — see below | Only if non-deterministic |

<Warning>
  **`200` does not mean approved.** It means the analysis completed. A detected impersonation attempt also returns `200`, with `spoofing: true`. Approval requires both conditions: `status === 200 && spoofing === false`.
</Warning>

## The two `422`s

The same status code covers two completely different problems with two different owners. **Tell them apart by the presence of `detail`, not by the HTTP code.**

<CodeGroup>
  ```json Image with no face theme={null}
  {
    "code": 422,
    "spoofing": true,
    "message": "No Face Detected",
    "id": "89f3f57e-...",
    "info": "onboarding-12345",
    "date": "2026-08-20",
    "time": "16:57:09"
  }
  ```

  ```json Invalid body theme={null}
  {
    "id": "4b3501fb-...",
    "code": 422,
    "message": "Bad request",
    "detail": [
      {
        "type": "string_type",
        "loc": ["body", "info"],
        "msg": "Input should be a valid string",
        "input": { "ref": "onboarding-12345" }
      }
    ]
  }
  ```
</CodeGroup>

**No face** is a capture problem: ask for a new photo with concrete instructions — face centred, good light, nothing in front of it. It is not a bug and retrying the same image will not fix it. Note that this response carries `spoofing: true`: if your code approves by exclusion, here it approves someone whose face it never even saw.

**Invalid body** is a code problem. `detail[].loc` tells you exactly which field is wrong; in the example, `info` was sent as an object when the contract asks for a string. It is fixed on your side and reproduces every time.

## `400`: the image fails a hard requirement

```json theme={null}
{
  "code": 400,
  "message": "Image should be larger than [224, 224]",
  "id": "f77e49f1-...",
  "info": "onboarding-12345"
}
```

Validate dimensions before calling. It is faster, cheaper, and lets you ask the user for a new capture without waiting for the round trip.

## `401`: credentials

```json theme={null}
{
  "statusCode": 401,
  "message": "Access denied due to invalid subscription key. Make sure to provide a valid key for an active subscription."
}
```

Note that this body uses `statusCode`, not `code`, and carries no `id`: it is rejected before a transaction is created. Check that the header is spelled exactly `Api-Key` and that the key matches the environment of the base URL you are calling. Mixing the UAT key with the production URL is the most common cause.

## `500`: not all of them are the service's

A `500` looks like a provider problem, but in practice most of them are caused by the request: of the five `500` bodies observed in testing, four originated in the request — an image the decoder could not process, a malformed payload.

**The reliable test is determinism:**

<Steps>
  <Step title="Retry the same request once">
    Same body, nothing changed.
  </Step>

  <Step title="Compare the error">
    If **the same** `error` comes back, the problem is in your request: check the image and the payload. If it differs or the call succeeds, it was transient.
  </Step>

  <Step title="If it is deterministic, stop retrying">
    File a ticket with the `id` and the error body. More retries only add load.
  </Step>
</Steps>

## Retry policy

```js theme={null}
const RETRYABLE = (status, body) =>
  status === 499 ||
  (status === 500 && !/image|payload/i.test(body?.error ?? ""));

// Maximum 2 retries, exponential backoff. Never on spoofing: true.
```

<Warning>
  Never retry a `200` response with `spoofing: true`. It is a verdict, not a failure. A retry that "fixes" a rejection is approving fraud.
</Warning>

## Filing a ticket

Write to [customer.support@vusecurity.com](mailto:customer.support@vusecurity.com) with:

| Detail | Why |
| - | - |
| The transaction `id` | It is the key support uses to find the case. Without it there is no lookup. |
| The environment | UAT and production can run different versions. |
| An approximate timestamp | It narrows the log window to search. |
| The full response body | With `code`, `message`, and `errorMessage` exactly as received. |

<Note>
  Do not attach the original image unless support explicitly asks for it through an agreed channel: it is biometric data belonging to a real person.
</Note>

<Card title="Back to the introduction" icon="face-viewfinder" href="/en/vucs/antispoofing-face/introduction">
  The decision rule, the endpoints, and authentication.
</Card>


## Related topics

- [Errors and diagnostics](/en/vucs/face-analysis/errors.md)
- [Reading the response](/en/vucs/antispoofing-face/responses.md)
- [Facial Antispoofing](/en/vucs/antispoofing-face/introduction.md)
- [Integration guide](/en/vucs/face-analysis/integration.md)


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