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

# Error Handling

> Learn what errors the Kombo API can return and how to handle them.

## Error Format

Proper error responses from the Kombo API will always follow this structure:

<CodeGroup>
  ```json Error Response highlight={4, 7} theme={null}
  {
    "status": "error",
    "error": {
      "code": "INTEGRATION.MODEL_NOT_AVAILABLE",
      "title": "This data model isn't supported for the selected integration.",
      "message": "The \"employees\" model is not yet available for Greenhouse. Please reach out to Kombo if you need this functionality.",
      "log_url": "https://app.kombo.dev/my-prod/logs?interactionId=123456"
    }
  }
  ```

  ```json Minimal Error Response theme={null}
  {
    "status": "error",
    "error": {
      "code": null,
      "title": null,
      "message": "An error without a code.",
      "log_url": null
    }
  }
  ```
</CodeGroup>

<ResponseField name="code" type="string | null" required>
  A unique identifier for programmatic error handling, used to determine the specific type of error that occurred. See the list below for all available codes.
</ResponseField>

<ResponseField name="title" type="string | null" required>
  A static, human-readable label. (Note: While we initially only used the *message* field, we are gradually moving static error descriptions to the *title* field).
</ResponseField>

<ResponseField name="message" type="string" required>
  A dynamic, detailed description of what went wrong in this specific instance.
</ResponseField>

<ResponseField name="log_url" type="string | null" required>
  A link to the [log page](/ats/features/logs) in the dashboard where you can investigate the issue yourself. If you need assistance, please share this link with our support team.
</ResponseField>

## Error Handling Recommendations

When building error handling logic, **always use the `code` field** if available to identify specific error types programmatically (see [the complete list of error codes](#error-codes) below):

```ts theme={null}
// NOTE: We do NOT recommend *also* checking on the HTTP status code -
// only checking the Kombo `code` field is enough
if (response.error.code === 'PLATFORM.RATE_LIMIT_EXCEEDED') {
  // Handle rate limit exceeded
}
```

Reality is messy and there will be rare cases where you might receive an error response that doesn't follow our typical structure, for example when our load balancer returns a 503 response due to an internal failure.

As a result, we recommend still having basic handling for when you don't receive a `code`:

```ts theme={null}
if (!response.error?.code) {
  // Handle generic error
}
```

Please **do not** write conditional logic based on the `message` field, as message text may change between releases. Similarly, **do not** rely on HTTP status codes or other response properties, as these may be updated for consistency across the API.

## Error Scenarios

The examples below demonstrate different error situations that can occur when using the Kombo API:

<AccordionGroup>
  <Accordion title="Kombo responds with validation error">
    **Scenario**: You submit a request with missing fields. Kombo validates inputs and rejects the request with a platform validation error.

    ```ts theme={null}
    await fetch('https://api.kombo.dev/v1/ats/candidates', {
      method: 'POST',
      headers: {
        Authorization: 'Bearer <API_KEY>',
        'Content-Type': 'application/json',
        'X-Integration-Id': '<INTEGRATION_ID>',
      },
      body: JSON.stringify({
        // the body content is missing
      })
    })
    ```

    ```json theme={null}
    {
      "status": "error",
      "error": {
        "code": "PLATFORM.INPUT_INVALID",
        "title": "Your request contains invalid data and failed validation.",
        "message": "candidate: Required; application: Required",
        "log_url": "https://app.kombo.dev/my-prod/logs?interactionId=123456"
      }
    }
    ```
  </Accordion>

  <Accordion title="Integration responds with categorized error">
    **Scenario**: You're building a job board that automatically applies candidates to positions. A candidate clicks "Apply" on a job they've already applied to previously.

    When you call `POST /ats/applications` to create the application, the ATS system (like Greenhouse) rejects it because the candidate already applied. However, Kombo categorizes this specific rejection with a structured error code:

    ```json theme={null}
    {
      "status": "error",
      "error": {
        "code": "ATS.APPLICATION_ALREADY_EXISTS",
        "title": "Candidate has already applied to this job.",
        "message": "John Doe (john@example.com) has an existing application for Software Engineer position",
        // ...
      }
    }
    ```

    **Error Handling**: You can check for this specific error code and handle it appropriately:

    ```ts theme={null}
    // ...call to create application...

    const body = await response.json()
    if (body.error.code === "ATS.APPLICATION_ALREADY_EXISTS") {
      showInfo("You've already applied to this position.")
      return
    }

    throw new Error("Application failed")
    ```
  </Accordion>

  <Accordion title="Integration system is unavailable">
    **Scenario**: The downstream API (ATS, HRIS, etc.) experiences downtime or maintenance. After internal retries, Kombo returns a categorized remote error.

    ```json theme={null}
    {
      "status": "error",
      "error": {
        "code": "REMOTE.SERVICE_UNAVAILABLE",
        "title": "The remote system is currently unavailable.",
        "message": "The API of \"Workday\" is currently unavailable. Please try again later.",
        "log_url": "https://app.kombo.dev/my-prod/logs?interactionId=123456"
      }
    }
    ```

    **Error Handling**: Implement retry with exponential backoff, or inform the user to try again later.
  </Accordion>
</AccordionGroup>

## FAQ

<AccordionGroup>
  <Accordion title="Why the `title` and `message`?">
    Let's imagine you get these two error responses:

    ```json theme={null}
    {
      "status": "error",
      "error": {
        "code": "REMOTE.INPUT_INVALID",
        "title": "The remote system returned validation errors.",
        "message": "Employee field 'department' is required for BambooHR",
        "log_url": null
      }
    }
    ```

    ```json theme={null}
    {
      "status": "error",
      "error": {
        "code": "REMOTE.INPUT_INVALID",
        "title": "The remote system returned validation errors.",
        "message": "Candidate field 'email' must be a valid email address for Greenhouse",
        "log_url": null
      }
    }
    ```

    They both have the `code` "REMOTE.INPUT\_INVALID" and the same `title` of "The remote system returned validation errors."

    However, while the `title` is always identical for this error code, the `message` varies completely depending on the integration. Each integration may format errors differently, and we don't guarantee any specific message format or structure.

    (Note: Below in the list of error codes, you can see the current `title` text for each error type.)
  </Accordion>

  <Accordion title="Is the `code` always present?">
    Not every error is categorized yet. So the `code` can also be `null`.

    If the `code` is currently `null` but a specific error type (like `ATS.JOB_CLOSED`) would make sense, please contact support.
  </Accordion>

  <Accordion title="Which errors can be safely retried?">
    Requests failing with [`PLATFORM.RATE_LIMIT_EXCEEDED`](#platform-rate_limit_exceeded), [`PLATFORM.CONCURRENCY_LIMIT_EXCEEDED`](#platform-concurrency_limit_exceeded), [`REMOTE.RATE_LIMIT_EXCEEDED`](#remote-rate_limit_exceeded) or [`REMOTE.SERVICE_UNAVAILABLE`](#remote-service_unavailable) are generally safe to retry. If our load balancer responds with HTTP `503`, you should retry the request as well.

    Validation errors ([`PLATFORM.INPUT_INVALID`](#platform-input_invalid) and [`REMOTE.INPUT_INVALID`](#remote-input_invalid)) can be retried after you correct the underlying input.

    For other errors, avoid automatic retries without human input. Use exponential backoff (preferably with jitter) for retries.
  </Accordion>
</AccordionGroup>

## Error Codes

Most errors include an error `code` that can be used to identify their cause and write application logic to handle them appropriately.

Since **new error codes may be added in the future**, your application logic should handle unknown error codes gracefully.
Below, you can find a list of all the error codes that can be returned by the API:

<Info>
  Some error codes appear in pairs with different namespaces to indicate their origin:

  * [`PLATFORM.RATE_LIMIT_EXCEEDED`](#platform-rate_limit_exceeded) and [`REMOTE.RATE_LIMIT_EXCEEDED`](#remote-rate_limit_exceeded)
  * [`PLATFORM.INPUT_INVALID`](#platform-input_invalid) and [`REMOTE.INPUT_INVALID`](#remote-input_invalid)
  * [`PLATFORM.UNKNOWN_ERROR`](#platform-unknown_error) and [`REMOTE.UNKNOWN_HTTP_ERROR`](#remote-unknown_http_error)

  `PLATFORM.*` errors come from Kombo while `REMOTE.*` errors (originally) come from the downstream API (ATS, HRIS, etc.).
</Info>

<Note>
  We're still finalizing our error categorization.
  Platform errors are already well-categorized, but not every remote system error is fully classified yet.
  If you notice a missing or miscategorized error, please let us know.
</Note>

***

### Namespace `PLATFORM`

All the errors related to the general Kombo platform.

#### `PLATFORM.RATE_LIMIT_EXCEEDED`

Title: "Rate limit exceeded."\
HTTP Status: 429 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

#### `PLATFORM.CONCURRENCY_LIMIT_EXCEEDED`

Title: "Concurrency limit exceeded."\
HTTP Status: 429 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

#### `PLATFORM.INTEGRATION_NOT_FOUND`

Title: "Integration not found."\
HTTP Status: 404 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

#### `PLATFORM.INPUT_INVALID`

Title: "Your request contains invalid data and failed validation."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Review the information that is being sent in the request, as there might be missing or invalid fields. Check the Logs for more details.
</Info>

#### `PLATFORM.UNKNOWN_ERROR`

Title: "An unknown error occurred in our system."\
HTTP Status: 500 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  This is the fallback error message, when an unexpected error has occurred on the side of Kombo.

  We're still improving our error categorization. If this seems like it should be a more *specific* error type (like `ATS.JOB_CLOSED`), please contact support.
</Info>

#### `PLATFORM.IP_NOT_WHITELISTED`

Title: "Your IP address is not whitelisted."\
HTTP Status: 403 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

#### `PLATFORM.AUTHENTICATION_INVALID`

Title: "The provided authentication is invalid."\
HTTP Status: 401 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

#### `PLATFORM.TASK_TIMED_OUT`

Title: "The task timed out."\
HTTP Status: 500 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  The task did not complete in time. This is usually a transient issue. Retry the request with the same idempotency key to resume processing.
</Info>

***

### Namespace `INTEGRATION`

All the errors related to the *connection* to a specific remote system.

#### `INTEGRATION.PERMISSION_MISSING`

Title: "A permission is missing in the remote system."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Check in the Kombo dashboard which permissions are missing. Review the connection guide for how to add them and inform your customer of the required steps. For some integrations, a re-connect may be necessary.
</Info>

#### `INTEGRATION.AUTHENTICATION_INVALID`

Title: "The integration cannot authenticate with the remote system."\
HTTP Status: 403 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Use the reconnection link to re-authenticate the integration. If this repeats, review the logs and contact Kombo support.
</Info>

#### `INTEGRATION.QA_FAILED`

Title: "The integration's setup sync failed quality checks."\
HTTP Status: 409 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  No action is required on your side. Kombo support is investigating. We will notify you if any input or changes are needed from your side.
</Info>

#### `INTEGRATION.SETUP_SYNC_PENDING`

Title: "The integration's setup sync is still running."\
HTTP Status: 409 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  To prevent incomplete or inconsistent data, API requests are blocked until the setup sync completes.

  For larger remote systems, the initial sync can take longer. Monitor progress in the Kombo dashboard.

  If it takes unusually long or appears stuck, contact Kombo support. We can review the job and, if appropriate, trigger a limited "recent data only" sync to speed up availability.
</Info>

#### `INTEGRATION.SETUP_INCOMPLETE`

Title: "The integration setup process is incomplete."\
HTTP Status: 409 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Some integrations require additional setup steps from the end customer beyond simply connecting their credentials. This can include configuring webhooks within the remote tool, setting up sources for ATS integrations, or configuring employee filters for HRIS. This error means the end customer has connected the integration but has not yet completed those required steps.

  To unblock the integration, generate a setup link from the integration's detail page and share it with the end customer, or open the setup flow on their behalf directly from the dashboard.

  As a last resort, dashboard admins can force-complete setup from the integration's "Issues" panel using the "Force unlock" button, but this should only be done if you are certain the missing steps are not required.
</Info>

<Info>
  The setup steps are already shown to your end customer at the end of a Kombo Connect session.

  If you would like to surface the setup experience to a customer in your UI outside of that flow, you can use the [Create Setup Flow link](/hris/v1/post-integrations-integration-id-setup-link) endpoint to generate a link and pass it to `showKomboConnect` from the Kombo Connect SDK, the same way you handle the initial connection flow. This lets your customers complete the remaining setup steps without leaving your product.
</Info>

#### `INTEGRATION.INACTIVE`

Title: "This integration is currently deactivated."\
HTTP Status: 403 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  In the Kombo Dashboard you can reactivate the integration.
</Info>

#### `INTEGRATION.MODEL_NOT_AVAILABLE`

Title: "This data model isn't supported for the selected integration."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Look at the "Coverage Grid" in the Kombo Dashboard for more details. Reach out to the Kombo support if you need this functionality.
</Info>

#### `INTEGRATION.MODEL_DISABLED`

Title: "This data model is disabled in the integration's scope configuration."\
HTTP Status: 403 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Go to the integration in the Kombo Dashboard. In the settings the "Scope config" is configured.
  Change this scope config to enable the functionality.
</Info>

#### `INTEGRATION.ACTION_NOT_AVAILABLE`

Title: "This action isn't supported for the selected integration."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Look at the "Coverage Grid" in the Kombo Dashboard for more details. Reach out to the Kombo support if you need this functionality.
</Info>

#### `INTEGRATION.ACTION_DISABLED`

Title: "This action is disabled in the integration's scope configuration."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Go to the integration in the Kombo Dashboard. In the settings the "Scope config" is configured.
  Change this scope config to enable the functionality.
</Info>

***

### Namespace `REMOTE`

All the errors originating from third-party HRIS/ATS systems.

#### `REMOTE.SERVICE_UNAVAILABLE`

Title: "The remote system is currently unavailable."\
HTTP Status: 500 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  This is usually due to scheduled maintenance or an outage on the vendor side. Check the logs for details. If it does not resolve within a few hours, please reach out to support.
</Info>

#### `REMOTE.RATE_LIMIT_EXCEEDED`

Title: "Kombo has hit the rate limit of the integration's API. Please try again later."\
HTTP Status: 429 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Kombo is already retrying requests to the remote system automatically. Only when the backoff exceeds what we can do in the request we abort and return this error.
</Info>

#### `REMOTE.INPUT_INVALID`

Title: "The remote system returned validation errors."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

#### `REMOTE.UNKNOWN_HTTP_ERROR`

Title: "The remote system returned errors."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  We're still improving our error categorization. If this seems like it should be a more *specific* error type (like `ATS.JOB_CLOSED`), please contact support.
</Info>

***

### Namespace `HRIS`

All the errors related to the HRIS use-case.

#### `HRIS.STAFFING_ENTITY_CLOSED`

Title: "The staffing entity is closed."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Ensure to only call our get employee form endpoint with open staffing entities.
</Info>

<Info>
  Select a different staffing entity (job/position/requisition) to create the employee for.
</Info>

#### `HRIS.EMPLOYEE_ALREADY_EXISTS`

Title: "The employee already exists in the HRIS system."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

***

### Namespace `ATS`

All the errors related to the ATS use-case.

#### `ATS.JOB_CLOSED`

Title: "The requested job is closed."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  This occurs when candidates try to apply to jobs that have been closed or archived in the ATS system. This is normal and not critical unless it happens frequently, which may indicate outdated job listings.
</Info>

<Info>
  Ensure your UI filters out closed jobs and refreshes job statuses regularly. When this error occurs, show the user that the job is closed.
</Info>

#### `ATS.APPLICATION_ALREADY_EXISTS`

Title: "The candidate has already applied to this job."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Show the candidate that they have already applied to the job. If your system created the first application, restrict the candidate from applying again.
</Info>

***

### Namespace `LMS`

All the errors related to the LMS use-case.

#### `LMS.COURSE_UPDATE_NOT_SUPPORTED`

Title: "Course updates are not supported for this tool."\
HTTP Status: 400 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  This integration does not support updating existing courses. You can only create new courses. If you need to update a course, deactivate it and create it again.
</Info>

***

### Namespace `AI_APPLY`

All the errors related to AI Apply.

#### `AI_APPLY.JOB_FEED_IMPORT_ALREADY_RUNNING`

Title: "This job feed already has a running import."\
HTTP Status: 409 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>

<Info>
  Ensure you do not start parallel imports for the same job feed. If this persists after the suggested retry time, check your logs and contact Kombo support.
</Info>

#### `AI_APPLY.JOB_FEED_IMPORT_TIMED_OUT`

Title: "The job feed import timed out."\
HTTP Status: 504 <Tooltip headline="Don't rely on HTTP status codes!" tip="Please always use the `code` response field to identify specific error types programmatically." cta="View details" href="#error-handling-recommendations"><Icon icon="circle-info" color="#9FA4A3" /></Tooltip>
