# Error Codes

## Error body

Every error, on every endpoint, has this shape:

```json
{
  "code": 404,
  "codeDescription": "ITEM_NOT_FOUND",
  "message": "Item not found"
}
```

| Field | Meaning |
| --- | --- |
| `code` | The HTTP status, repeated. Always present. |
| `message` | A sentence for a person. Always present; not stable. |
| `codeDescription` | A stable identifier for the specific error, when the endpoint distinguishes several. Branch on this, not on `message`. |
| `data` | Extra detail for some errors — for instance, the Items that already exist when creating one would duplicate a connection. |

## Status codes

| Status | Meaning | Usually because |
| --- | --- | --- |
| `400` Bad Request | The request is invalid. | A missing or malformed field. |
| `401` Unauthorized | The credential is missing, wrong or expired. | An API Key past its 2 hours, or wrong `clientId`/`clientSecret` on `POST /auth` (`CLIENT_KEYS_UNAUTHORIZED`, `CLIENT_DISABLED`). |
| `403` Forbidden | The credential cannot reach this resource. | A Connect Token used outside its scope — see [Authentication](/reference/authentication). |
| `404` Not Found | No such resource. | An `id` that does not exist. |
| `405` Method Not Allowed | The endpoint does not support this verb. | |
| `406` Not Acceptable | A format other than JSON was requested. | |
| `409` Conflict | The request contradicts the current state of the resource. | A conflict updating an Item — see [`PATCH /items/{id}`](/reference/items/items-update). |
| `429` Too Many Requests | A rate limit was exceeded. | See [Rate Limits](/reference/rate-limits) for the limits and the `Retry-After` header. |
| `500` Internal Server Error | Something failed on our side. | Retry later. |
| `503` Service Unavailable | Temporarily offline for maintenance. | Retry later. |

Each endpoint's page in this reference lists the statuses it returns and, where the API distinguishes them, the `codeDescription` values.

## Creating and updating an Item

These come back from [`POST /items`](/reference/items/items-create) and
[`PATCH /items/{id}`](/reference/items/items-update). Where the text below shows a
`:placeholder`, the real message carries the value — a frequency, a wait, a
parameter name.

| `codeDescription` | Status | Message | What to do |
| --- | --- | --- | --- |
| `PARAMETERS_NOT_PROVIDED` | `400` | parameters were not provided | Send the connection's credentials to sync the item. |
| `ITEM_ALREADY_UPDATING` | `400` | An update is already in progress, wait until the last execution ends | This item is syncing. Wait for the execution to finish — success or error — before triggering another. |
| `ITEM_IS_ALREADY_UPDATING` | `400` | There is an active item for the set of credentials that hasn't finished executing | The same set of credentials is syncing on another item. Wait for it, so two sessions are not opened with the institution at once. |
| `CLIENT_IS_UPDATING_BEFORE_ALLOWED_FREQUENCY` | `409` | Client updates on this item are allowed at most every :minUpdateFrequencyAllowedInHours hours. Last update was at :lastUpdatedAt | Wait until the minimum frequency has passed since the last update. The limit is per team and adjustable — ask support if your use case needs a shorter one. |
| `LAST_EXECUTION_HAD_LOGIN_ERROR` | `400` | Last execution had a login error, you must update the parameters | The last sync failed to log in. Send new credentials before updating again. |
| `TOO_MANY_CONSECUTIVE_LOGIN_FAILURES` | `400` | must wait at least :readableBackoffTime after :maxConsecutiveFailedLoginAttempts consecutive login errors, last attempt was at :lastExecutionEndedAt (can retry after: :canRetryAfterDate) | A cooldown after repeated login errors, so the user's account is not locked by the institution. Retry after the time in the message. |
| `TOO_MANY_CONSECUTIVE_ERRORS` | `400` | There has been more than 5 failing syncronizations, please contact support | The connection failed too many times in a row. Report it to support with the `itemId`. |
| `ITEM_IN_ERROR_COOLDOWN` | `409` | This set of credentials recently failed to connect and is in a cooldown period, please try again later | These credentials failed recently and are in a cooldown. Retry after it passes. |
| `CONNECTOR_OFFLINE` | `409` | this connector is offline in this moment | The connector is not accepting executions right now. Try again later — see [status.pluggy.ai](https://status.pluggy.ai). |
| `CONNECTOR_REQUIRED_PARAMETER_VALIDATION_ERROR` | `400` | The parameter :parameter is required to be renewed for item update. | The connector now requires that parameter again. Send it to update the connection. |
| `ITEM_ORIGINAL_CONNECTED_WITH_DIFFERENT_ACCOUNT` | `409` | Item was originally connected with a different account, please use the original account | The credentials now point at a different account than the one the item was created with. Use the original account, or create a new item. |
| `ITEM_CREATION_LIMIT_EXCEEDED` | `409` | Client exceeded item creation limit (:itemsLimit items) for the current subscription level. | You reached the item limit of your subscription. Delete unused items or contact support. |
| `CLIENT_HAS_ITEM_UPDATES_DISABLED` | `409` | Client has item updates disabled | Updates were disabled for the team. Contact support. |
| `CREATE_ITEMS_API_FREE_DISABLED` | `400` | Free subscription can only create items through our Connect Widget | On the free subscription, items are created through the Connect Widget. |
| `SANDBOX_CLIENT_ITEM_UPDATE_NOT_ALLOWED` | `400` | Current client subscription level can only update Sandbox (Pluggy Bank) items | Your subscription level only allows updating Sandbox (Pluggy Bank) items. |

## MFA errors

Returned when sending a multi-factor parameter to an Item — see
[Updating an Item](/docs/connect-widget/updating-item).

| `codeDescription` | Status | Message | What to do |
| --- | --- | --- | --- |
| `ITEM_MFA_NOT_FOUND` | `404` | item has no mfa input request | The item is not waiting for an MFA input, so none can be submitted. |
| `ITEM_MFA_ALREADY_PROVIDED` | `400` | item has no mfa input request, it was already provided | Nothing to do — the MFA was already submitted. |
| `ITEM_MFA_EXPIRED` | `400` | Item's MFA parameter expired, please start a new update | The MFA window closed. Start a new update to sync the connection. |
| `ITEM_MFA_PARAMETER_EXPECTED_MISMATCH` | `400` | Item is expecting ':parameter' MFA param name | The item is waiting for a different parameter. Use the name in the message. |
| `MFA_PARAMERTER_WAS_ALREADY_USED_ERROR` | `400` | MFA parameter has to be updated from last execution | The value sent is the one already used in the last execution. Ask the user for a new one. |

<Callout variant="info" title="MFA_PARAMERTER_WAS_ALREADY_USED_ERROR">
That spelling is not a typo in this page: the API returns `PARAMERTER`. Match it
exactly if you branch on it.
</Callout>

Read the guide: [Errors Codes](/docs/developer-tools/error-codes).