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

# Errors

> The single error envelope, how to handle failures, and the complete code catalogue.

Every failure the API returns — from a typo in a filter to an internal fault — uses the same JSON envelope and an appropriate HTTP status code. There is exactly one shape to parse, so your error handling is one code path.

```json theme={null}
{
  "error": {
    "code": "LIST_NOT_FOUND",
    "message": "The requested list was not found.",
    "param": null,
    "doc_url": "https://docs.fuseai.com/concepts/errors#list_not_found",
    "request_id": "req_8f3a1b2c9d4e"
  }
}
```

## The envelope

| Field | Type | Description |
| - | - | - |
| `code` | string | Stable, machine-readable identifier. This is the contract: codes never change meaning, so branch your logic on `code`. |
| `message` | string | Human-readable explanation, suitable for logs. Messages may be reworded at any time — never match on them. |
| `param` | string or null | The offending request field when validation fails; `null` otherwise. |
| `doc_url` | string or null | Link to the code's section in this catalogue. |
| `request_id` | string or null | Unique identifier for the request, also returned in the `x-request-trace-id` response header. Quote it when contacting support — it lets us find the exact request in our logs. |

## Status codes

The HTTP status tells you the class of failure; the `code` tells you the specific one.

| Status | Meaning |
| - | - |
| `400` | The request is missing a required part, such as the file on an import. |
| `401` | The API key is missing, malformed, expired, or revoked — see [Authentication](/authentication). |
| `402` | The workspace does not have enough [credits](/concepts/credits) for the operation. |
| `403` | The key is valid but not allowed this call: a missing [scope](/concepts/scopes), a plan or team restriction, or an action only the owner can take. |
| `404` | The endpoint or resource does not exist (or is not visible to your workspace). |
| `409` | The request conflicts with current state — for example, a list name that is already taken. |
| `422` | The request failed validation, or is well-formed but semantically invalid — a missing required field, or a list with no contacts reachable on the requested channels. `param` names the offending field where possible. |
| `429` | Rate limit exceeded — see [Rate limits](/concepts/rate-limits). |
| `500` | An unexpected error on our side. The body may be sparse, but it is still enveloped. |

## Handling failures

**Branch on `code`, never on `message`.** Codes are stable identifiers; messages are prose we may reword to be clearer. An integration that string-matches messages will break on a copy edit.

**A `404` does not always mean "never existed."** The API never confirms that another workspace's resources exist, so a `404` on an id you believe you own can also mean the resource belongs to a different workspace. This is deliberate: it prevents anyone from probing ids to map out other tenants' data.

**Retry `429` and `500`; fix everything else.** On `429`, honor the `Retry-After` header before retrying — see [Rate limits](/concepts/rate-limits) for the windows. On `500`, GET requests are safe to retry with backoff; for writes, confirm whether the operation took effect before re-issuing it. Statuses in the 401–422 range describe a problem with the request itself — retrying the same request will fail the same way, so correct it first (for validation errors, `param` points at the field to fix).

### Example: a 404 in full

Requesting rows from a list id that does not exist in your workspace:

```bash theme={null}
curl https://api.tryfuse.ai/api/v1/business/lists/64f1a2b3c4d5e6f7a8b9c0d1/rows \
  -u "af_YOUR_KEY:"
```

```json theme={null}
{
  "error": {
    "code": "LIST_NOT_FOUND",
    "message": "The requested list was not found.",
    "param": null,
    "doc_url": "https://docs.fuseai.com/concepts/errors#list_not_found",
    "request_id": "req_8f3a1b2c9d4e"
  }
}
```

## Error code catalogue

Every code the API returns, grouped by area. `doc_url` in a live error response links to the matching section below.

### UNAUTHORIZED

`401` — The API token is missing, malformed, expired or revoked. Check that you are sending the key as the Basic-auth username with an empty password, and that the key has not been revoked in API Cockpit — see [Authentication](/authentication).

### INSUFFICIENT\_SCOPE

`403` — This API token is not scoped for this endpoint. The key itself is valid; it was created without the scope this endpoint requires. Use a key that carries the scope — see [Scopes](/concepts/scopes).

### FORBIDDEN

`403` — The account's plan does not include API access.

### TEAM\_MEMBER\_NOT\_IN\_SCOPE

`403` — `POST /business/credits/usage` named a `memberIds` entry who is not an active member of your team.

### ENDPOINT\_NOT\_FOUND

`404` — No endpoint matches this path and method. Check for typos in the path and confirm the HTTP method against the [API reference](/api-reference); a `POST` to a `GET`-only path returns this code.

### RATE\_LIMITED

`429` — You have exceeded the rate limit. Wait for the window to reset before retrying, honoring the `Retry-After` header — see [Rate limits](/concepts/rate-limits).

### VALIDATION\_FAILED

`422` — The request failed validation against the endpoint's schema: a missing required field, a value of the wrong type, or a value outside its vocabulary. Most endpoints ignore body fields they do not recognise; some reject them, as the [API reference](/api-reference) notes per endpoint. `param` names the offending field and `message` says what was wrong with it; when more than one field fails, `message` lists them all. Fix the request before retrying — the same payload will keep failing.

### INVALID\_REQUEST

`422` — The request passed schema validation but a value could not be used: a column value that cannot be coerced to the column's type, or a campaign channel combination that is not supported. Correct the value and retry. It can also come back as `400`, `403`, `404` or `409` when an upstream service rejects the request for a reason this API does not name.

### UNEXPECTED\_ERROR

`500` — An unexpected error occurred. Retry GET requests with backoff; for writes, verify state first. If it persists, contact support with the `request_id`.

### INSUFFICIENT\_CREDITS

`402` — The workspace does not have enough credits for the operation. Operations that check the balance up front reject the request before any work is billed. Work that is charged as it runs stops or pauses when the balance runs out instead; [Credits](/concepts/credits#insufficient-balance) lists which is which.

### LIST\_NOT\_FOUND

`404` — No list with that id is visible to your workspace. Verify the id against `GET /business/lists`; an id belonging to another workspace also returns this code.

### LIST\_NAME\_TAKEN

`409` — A list with that name already exists in your workspace. Pick a different name, or add to the existing list instead of creating a new one.

### LIST\_NAME\_AMBIGUOUS

`409` — More than one list in your workspace has the name you passed in `listName`, so create-or-reuse cannot pick a destination — silently choosing one would pour contacts into the wrong list. Reference the destination by `listId` instead (`GET /business/lists` shows ids).

### LIST\_NAME\_RESERVED

`422` — The `listName` is a system list title ("All Saved Contacts", "All Enriched Contacts", and the other built-ins). System lists cannot be created or written to as a save destination; pick another name.

### LIST\_PROCESSING

`409` — The source list is still being built or enriched, so a derived company list cannot be started from it yet. Poll `GET /business/lists/{listId}` until its `completionStatus` settles, then retry.

### COLUMN\_NAME\_TAKEN

`409` — The list already has a column with that name. Column names are unique per list; rename the new column or update the existing one — see [Custom columns](/guides/custom-columns).

### COLUMN\_NAME\_RESERVED

`422` — The name is one of the reserved built-in column names (name, first name, last name, job title, company, email, phone …).

### COLUMN\_NOT\_FOUND

`404` — No column with that id exists on this list.

### SEARCH\_FILTERS\_INVALID

`422` — The search filters could not be interpreted. Check filter keys and values against `GET /business/prospects/filter-options`, and see [Build a list from search](/guides/build-a-list-from-search) for working examples.

### SAVED\_SEARCH\_NOT\_FOUND

`404` — No saved search with that id is visible to your workspace. List available saved searches with `GET /business/saved-searches`.

### SAVED\_SEARCH\_INVALID

`422` — The saved search exists but its stored filters cannot be run as-is. Recreate or fix the search in the app, then run it again.

### SAVED\_SEARCH\_NAME\_AMBIGUOUS

`409` — More than one saved search in your workspace has the name you passed in `savedSearchName`. Names are labels, not identifiers, so the API never silently picks one. Reference the search by id (`GET /business/saved-searches` lists ids), or rename one of the duplicates.

### SAVED\_SEARCH\_FILTERS\_UNSUPPORTED

`422` — A filter field in the request cannot be stored in a saved search; `param` names it. Saved searches round-trip through the Fuse app's filter rail, and this field has no stored representation there — run it as a direct search instead of saving it, or drop the field from the saved version.

### SAVED\_SEARCH\_TYPE\_MISMATCH

`422` — The saved search is the wrong kind for this endpoint: a company search sent to people search, or a people search sent to company search. `param` is `savedSearchId`. Run it on the endpoint that matches its type.

### QUERY\_FILTERS\_INVALID

`422` — The natural-language `query` could not be converted into a runnable filter set — it was too vague to yield any concrete filter. Name concrete criteria (titles, locations, industries, company sizes), or pass structured `filters` directly. See [Build a list from search](/guides/build-a-list-from-search).

### EXCLUDE\_COMPANY\_LISTS\_INVALID

`422` — One or more ids in `excludeCompanyLists` do not resolve to company lists visible to your workspace. Check the ids and that each references a company list, not a contact list.

### CONTACT\_NOT\_FOUND

`404` — No contact with that id is visible to your workspace. Contacts belonging to another workspace also return this code.

### CONTACT\_LIST\_REQUIRED

`422` — The source list is a company list; companies are derived from a contact list's rows.

### CONTACT\_NOT\_IN\_LIST

`422` — One or more `contactIds` are not rows of this list. Send row ids from `GET /business/lists/{listId}/rows`.

### EXPORT\_NOT\_FOUND

`404` — No export job matching that id was found (it may have expired). Start a new export and poll the fresh job id — see [Export a list](/guides/export-a-list).

### EXPORT\_LIMIT\_EXCEEDED

`422` — The campaign has more leads than a single export may contain.

### CAMPAIGN\_NOT\_FOUND

`404` — No campaign with that id is visible to your workspace. Campaigns belonging to another workspace also return this code.

### CAMPAIGN\_NAME\_AMBIGUOUS

`409` — More than one campaign has the name you passed in `campaignName`. Names are labels, not identifiers, so the API never silently picks one — reference the campaign by id.

### CAMPAIGN\_LIST\_CAP\_REACHED

`422` — The campaign already carries its maximum number of attached lists (10), so the requested attach cannot happen. Detach a list in the app, or target a different campaign. Rejected before the save starts, so nothing is billed.

### ALL\_CONTACTS\_ALREADY\_ENRICHED

`409` — Every contact in the destination list already carries the enrichment the request asked for, so there is nothing to run (and nothing is billed). Save with `enrich: "none"`, request a different enrichment, or target a different list.

### CAMPAIGN\_NOT\_APPROVABLE

`409` — The campaign is not in a state that can be approved — it may already be approved or otherwise past the approval step. Fetch the campaign to check its current state — see [Campaigns](/guides/campaigns).

### CAMPAIGN\_NOT\_READY

`422` — The campaign is missing something it needs to send: a source list, a `ctaLink` on an AI-generated campaign, step content (a subject and body, or a topic), or a connected sending account for one of its channels. Fix it, then approve again; polling will not help. See [Campaigns](/guides/campaigns#troubleshooting-approval).

### CAMPAIGN\_BUSY

`409` — Another approve or stop is holding this campaign's activation lock. Retry in a few seconds.

### CAMPAIGN\_INITIALIZING

`409` — You sent `listIds` to `PATCH /business/campaigns/{campaignId}` while an AI-generated campaign's background initialization was still running. The source lists are checked against the campaign's sequence channels, and those are not settled until the steps have been generated. Poll `GET /business/campaigns/{campaignId}` until `initializationStatus` is `completed` (or `failed`), then retry. Other fields in the same request are unaffected — only `listIds` waits. Manual and template-based campaigns are initialized on creation and never return this code.

### INVALID\_CAMPAIGN\_CHANNELS

`422` — The `channels` value is not a valid channel combination for this campaign. Check the accepted values in the [API reference](/api-reference).

### INVALID\_ROW\_FILTERS

`422` — The `filters` value is not a valid row-filter object.

### LIST\_INCOMPATIBLE\_WITH\_CHANNELS

`422` — The list has no contacts reachable on the requested channels — it is empty, or no contact has an email address (or LinkedIn profile) for them. Enrich the list or choose channels its contacts can actually be reached on. Returned by `POST /business/campaigns` for the requested `channels`, and by `PATCH /business/campaigns/{campaignId}` when the new `listIds` cannot serve the campaign's existing steps. When several lists are given they are judged together: one list with emails plus one with only LinkedIn profiles is fine for an email + LinkedIn sequence.

This can also appear transiently on a list populated moments ago: reachability stats are computed asynchronously, so a just-filled list may report as incompatible until they catch up. Retry after a minute or two before treating it as a real incompatibility.

### LIST\_EMPTY

`422` — The list has no contacts to work with: there are no companies to derive from it, or an export found no members or no exportable data. On an export it arrives as the job's `error`.

### SEQUENCE\_STEP\_NOT\_FOUND

`404` — No sequence step with that id exists on this campaign. List the campaign's steps with `GET /business/campaigns/{campaignId}/steps` to get valid step ids.

### CONNECTION\_NOTE\_TOO\_LONG

`422` — The `body` you sent for a `linkedin_connection` step is longer than the 200 characters LinkedIn allows in a connection-request note. On this step type `body` is the note itself, so shorten it to 200 characters or fewer (an empty `body` sends the request without a note). Other step types keep their usual body limit.

### SCHEDULED\_SEND\_NOT\_FOUND

`404` — No queued send with that id is visible to your workspace. Send ids come from `GET /business/campaigns/{campaignId}/scheduled-sends`; an id belonging to another workspace also returns this code.

### SCHEDULED\_SEND\_NOT\_EDITABLE

`409` — The send can no longer be edited: only a send still waiting to go out (`scheduled` or `approval_required`) accepts `PATCH /business/scheduled-sends/{sendId}`. A send that was already sent, skipped, stopped, overwritten by an earlier edit, or is waiting on a task is settled.

### SCHEDULED\_SEND\_NOT\_SKIPPABLE

`409` — The send is already settled (sent, stopped, overwritten, replied or failed) and cannot be skipped.

### TEMPLATE\_NOT\_FOUND

`404` — The `templateId` does not resolve to a template visible to your workspace. Check the id, or omit it to let the campaign generate copy without a template.

### WRITING\_STYLE\_NOT\_FOUND

`404` — The `writingStyleId` does not resolve to a writing style visible to your workspace. Check the id against the styles configured in the app.

### KNOWLEDGE\_HUB\_NOT\_FOUND

`404` — The `knowledgeHubId` does not resolve to a knowledge hub visible to your workspace. List available hubs with `GET /business/knowledge-hubs` — see [Knowledge hubs](/guides/knowledge-hubs).

### AGENT\_NOT\_FOUND

`404` — The `agentId` does not resolve to an agent in your workspace. List agents with `GET /business/agents`.

### AGENT\_CONFIG\_MISSING

`409` — The draft carries no stored config to work from (a legacy draft saved before configs were persisted). Create the agent again.

### AGENT\_LIMIT\_REACHED

`403` — Free-plan accounts may hold at most 10 agents, drafts included. Delete an agent or upgrade the plan.

### AGENT\_NOT\_A\_DRAFT

`409` — The agent is not a draft (status is not `initializing`): it was already started, or is paused, expired or failed. Only drafts are editable and activatable — duplicate the agent and work on the copy.

### AGENT\_NOT\_RUNNING

`409` — The agent has nothing to pause: it is still a draft (`initializing`), or its provider subscription is already gone. Drafts are refused deliberately, because a paused draft could never be started again (activate accepts drafts only).

### AGENT\_PROCESSING

`409` — A run is in progress (status `processing`); the agent cannot be changed until it settles. Retry once it is `active` or `paused`.

### AGENT\_SIGNAL\_REJECTED

`422` — Web-monitor only: the search provider refused the `prompt` as a searchable signal. Rewrite the prompt rather than retrying it.

### AGENT\_SOURCE\_LIST\_EMPTY

`422` — The source list holds nothing this agent kind can watch — no LinkedIn URLs, no companies, or no trackable contacts. Fill the list first.

### AGENT\_TYPE\_UNSUPPORTED

`409` — The agent is of a legacy kind this API can no longer edit or activate; its `type` reads as null.

### RESEARCH\_RUN\_NOT\_FOUND

`404` — The `runId` does not resolve to a research run in your workspace.

### KNOWLEDGE\_HUB\_DEFAULT\_UNDELETABLE

`409` — The default knowledge hub cannot be deleted. Make another hub the default with `POST /business/knowledge-hubs/default`, then delete this one.

### KNOWLEDGE\_HUB\_NOT\_READY

`409` — The hub is still building (its `status` is `processing`), or never finished building, so this action cannot run yet. Poll `GET /business/knowledge-hubs/{hubId}` until it is `complete`.

### KNOWLEDGE\_HUB\_ALREADY\_EXISTS

`409` — Your team already has a knowledge hub that is built or building, and a team holds one. Add to it with `PATCH /business/knowledge-hubs/{hubId}` instead.

### KNOWLEDGE\_PAGE\_NOT\_FOUND

`404` — The `pageId` does not resolve to a page on this hub. List pages with `GET /business/knowledge-hubs/{hubId}/pages`.

### KNOWLEDGE\_HUB\_OWNER\_ONLY

`403` — The hub belongs to a teammate; you can read it, but only its owner can make it their default hub.

### KNOWLEDGE\_HUB\_PAGES\_UNAVAILABLE

`409` — The hub predates knowledge pages and cannot be refreshed.

### KNOWLEDGE\_HUB\_WEBSITE\_NOT\_FOUND

`404` — `url` is not one of the hub's websites.

### KNOWLEDGE\_PAGE\_NOT\_REGENERABLE

`409` — The page has no cached sources to rebuild from (you authored it, or its sources were removed).

### LEARNED\_FACT\_NOT\_FOUND

`404` — The `factId` does not resolve to a learned fact for your team.

### LEARNED\_FACT\_NOT\_ANONYMIZED

`422` — The new claim contains an email address, a phone number, a deal amount or contract terms. Names are not checked, so keep them out yourself.

### ATTACHMENT\_NOT\_FOUND

`404` — The note has no attachment (or the note id is wrong). Note ids come from the hub detail response.

### ATTACHMENT\_ALREADY\_EXISTS

`409` — The note already holds a document; delete the note's attachment first.

### JOB\_NOT\_FOUND

`404` — The `jobId` does not resolve to an async job for your workspace. Job ids come from `202` responses.

### SCAN\_NOT\_FOUND

`404` — No duplicate scan with that `scanJobId` exists for your workspace, or it has expired. Start a new scan.

### SCAN\_NOT\_COMPLETED

`409` — The merge named a scan that is still running. Poll `GET /business/contacts/dedupe-jobs/{jobId}` until it is `completed`.

### SCAN\_HAS\_NO\_GROUPS

`422` — The scan found no duplicates, so there is nothing to merge.

### IMPORT\_NOT\_FOUND

`404` — The `importId` does not resolve to an upload of yours. Import ids come from `POST /business/imports` and `POST /business/imports/presign`.

### IMPORT\_FILE\_MISSING

`400` — `POST /business/imports` needs either a multipart `file` part or an `importId` from a completed presigned upload.

### IMPORT\_FILE\_UNSUPPORTED

`422` — The file could not be parsed. Supported formats: CSV, XLS, XLSX.

### IMPORT\_FILE\_TOO\_LARGE

`422` — The file is over the limit for this intake. Multipart accepts up to 10MB; use `POST /business/imports/presign` for files up to 50MB.

### IMPORT\_FILE\_EMPTY

`422` — The file parsed but has no data rows.

### IMPORT\_ALREADY\_COMMITTED

`409` — This import was already committed, and a commit runs once. Upload the file again to import it again.

### IMPORT\_IDENTITY\_MISSING

`422` — No column maps to `LinkedIn URL`, `Email`, or a name plus `Company Domain`, so the rows could not be matched. `param` is `mapping`; map one of those columns explicitly.

### CITY\_FILTER\_UNRESOLVED

`422` — NOT ONE of the `filters.headquartersCity` names geocoded to a city area, so the search was refused rather than run worldwide; names that do geocode are OR-ed together and a name that does not is dropped, so this fires only when every name fails. `param` is `filters.headquartersCity`.

### CREDIT\_LIMIT\_EXCEEDS\_PLAN

`422` — The requested monthly credit limit is higher than the plan's credit allowance.

### CRM\_NOT\_CONNECTED

`422` — This CRM is not connected for your workspace — connect it in the app's integration settings.

### FOLDER\_NAME\_TAKEN

`409` — A folder with this name already exists for this list kind.

### FOLDER\_NOT\_FOUND

`404` — The requested folder was not found.

### NOTE\_NOT\_FOUND

`404` — No note with that id on this hub.

### NO\_LEADS\_TO\_EXPORT

`422` — The campaign exists but has no enrolled leads to export yet.

### NO\_ROWS\_TO\_RESEARCH

`422` — No row on the list matches `filters`, so there is nothing to research and nothing was charged.

### PRIMARY\_VALUE\_NOT\_ON\_CONTACT

`422` — The value must be one the contact already carries — primaries promote, never invent.

### PROVENANCE\_NOT\_FOUND

`404` — The column exists but no run has computed that row, so there is no provenance to show.

### PROVIDERS\_NOT\_SUPPORTED

`422` — ProviderIds was sent for a standard-engine column; only a deep\_research column can be restricted to specific providers.

### RUN\_ALREADY\_TERMINAL

`409` — The run has already finished (completed, failed or cancelled) and cannot be cancelled.

### STEP\_ORDER\_INVALID

`422` — A linkedin\_connection step would follow a linkedin\_message step.

### STEP\_POSITION\_TAKEN

`409` — A step already occupies this sequenceNumber in the campaign.

### STEP\_PREVIEW\_UNAVAILABLE

`422` — There is nothing to render this step against: the campaign has no source list or no contact to sample, or generation produced no preview.

### WEBSITE\_TRACKING\_NOT\_SET\_UP

`404` — This account has no website-tracking record (no Webtraffic entry, or the caller resolves to no team owner) — set website tracking up in the app first.


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