# Errors for Plan

> Every error code the Dailybot Plan API (Beta) returns, with its HTTP status, what it means and what to do next, including 402 during the Beta.

Language: en
Canonical: https://www.dailybot.com/developers/plan/errors
Markdown: send header `Accept: text/markdown` on any URL to receive Markdown instead of HTML.
Last Updated: 2026-09-29

---

> **Beta** — Plan is in beta. Everything under `/plan` in the web app, the CLI and agent skill commands for projects, goals, boards and tasks, and the `/v1/plan/` public API may change before general availability. Want to try it with your team? Write to **support@dailybot.com**.

Every Plan error answers with an HTTP status and a JSON body. Branch on the machine-readable `code`, never on the human-readable `detail`:

```json
{
  "detail": "This task changed since you loaded it.",
  "code": "version_conflict",
  "extra": { "current_version": 9 }
}
```

Validation errors on a request body answer `400` with a map of messages per field instead, and **no `code` key**. For example, a board created without its project:

```json
{ "project": ["This field is required."] }
```

Check for `code` first; when it is absent, read the field map. The rules shared by every Dailybot API, including retries, are in [Errors](/developers/errors).

<h2 id="beta-402">During the Beta, 402 is expected</h2>

Until your organization is enabled for the Plan Beta, every Plan endpoint answers **`402 plan_upgrade_required`**, whatever credential you use. That is expected, not a bug: write to **support@dailybot.com** to join. `GET /v1/plan/entitlements/` is the one Plan endpoint that never answers `402`, so you can check the state first.

<h2 id="402-vs-503">402 and 503 mean different things</h2>

| Response | Meaning | Reads | Writes |
|---|---|---|---|
| `402 plan_upgrade_required` | Plan is **not enabled** for your organization (a plan or Beta question) | Refused | Refused |
| `503 feature_temporarily_read_only` | Plan is **temporarily read-only** during an incident | Keep working | Refused, retry later |

Handle them separately. A `503` never means you lost access: reads keep working so you can always export your work.

<h2 id="not-found">404 never reveals what exists</h2>

A task, board or project that does not exist and one that belongs to another organization return the **same `404` body**. Filters behave the same way: a board key that names nothing of yours simply matches nothing.

<h2 id="codes">All codes</h2>

<h3 id="status-400">400 Bad Request: the request could not be accepted as sent</h3>

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `actor_required` | 400 | The call needs a person, but the credential is an agent or organization key (for example `owner=me`). | Use a login session or a personal API key, or pass a user uuid instead of `me`. |
| `attachment_invalid_type` | 400 | The file type is not supported. Accepted: PNG, JPEG, GIF and WebP images; PDF; plain text and Markdown; ZIP; Word, Excel and PowerPoint files. The server checks the file's actual content, not only its declared type. | Upload a supported file type. |
| `attachment_limit_reached` | 400 | The task, comment, goal or project already has 50 attachments, the maximum. | Remove an attachment before adding another. |
| `attachment_too_large` | 400 | The file is larger than allowed: 25 MiB with presigned task uploads, 5 MiB in a single multipart request (the only way to attach to a comment, goal or project) or on servers without object storage. `extra.max_size_bytes` states the limit. | On a task, use presign → upload → confirm; otherwise send a smaller file. |
| `channel_not_found` | 400 | A channel id the connected platform does not know, or a private channel where a public one is required (`extra.parameter: "channel"`). | Pick an `external_id` from `GET /v1/plan/channels/` (`type=channel` for a personal destination). |
| `comment_body_too_long` | 400 | The comment is longer than 10,000 characters. | Shorten it, or split it into several comments. |
| `delta_window_expired` | 400 | The delta cursor is older than 7 days. | Read the board snapshot again and continue from its `delta_cursor`. |
| `description_too_long` | 400 | The task's description is longer than 50,000 characters. | Shorten it or move the detail into an attachment. |
| `favorite_limit_reached` | 400 | You already have 50 favorites. | Unpin one before pinning another. |
| `idempotency_key_required` | 400 | A bulk call was sent without an `Idempotency-Key`. | Add the header; bulk always requires it. |
| `invalid_agent_attribution` | 400 | The agent name is longer than 128 characters, uses characters outside letters, numbers, spaces and `. - _ ( ) ' # + / & , :`, belongs to a deactivated agent, or the value in `X-Dailybot-Agent-Name` cannot be decoded as percent-encoded UTF-8; or an agent-type key sent an agent name. Names are never truncated. | Shorten the name and percent-encode the header, or drop the name when calling with an agent key. See [Conventions for Plan](/developers/plan/conventions#agent-attribution). |
| `invalid_date_range` | 400 | A date or date range is malformed (dates are `YYYY-MM-DD`). | Fix the date format. |
| `invalid_filter_value` | 400 | A filter, `include` token or query value could not be parsed (for example `state=overdue`). `extra.parameter` names it. | Fix the value; see [Conventions for Plan](/developers/plan/conventions#filters). |
| `invalid_idempotency_key` | 400 | The `Idempotency-Key` is not a valid key (8 to 128 characters). | Send a key of 8 to 128 characters, for example a UUID. |
| `invalid_label_filter` | 400 | A `label` filter value is not a label uuid, or there are more than 50. | Send up to 50 label uuids. |
| `invalid_relation` | 400 | The link or reference is not valid. Examples: a task related to itself or to a task in another workspace, a task made its own parent, the task's `blocks` limit reached, a reply to a reply (threads are one level deep), a reply to a comment on another task, or an unknown bulk operation. `detail` says which. | Read `detail` and fix the reference. |
| `invalid_schedule` | 400 | A report or briefing schedule field is invalid: `extra.parameter` is `weekdays`, `time`, `timezone`, `channel` or `kind`. | Send ISO weekdays 1–7 (exactly one for a weekly report), `HH:MM`, an IANA timezone, and a channel or email recipients. |
| `invalid_sort` | 400 | The `sort` value is not supported by this list. | Use a sort key the endpoint documents. |
| `last_done_state` | 400 | A board must keep at least one live column in the `done` category; archiving or re-categorizing the last one is refused. | Add another `done` column first. |
| `milestone_not_on_project` | 400 | The milestone belongs to a different project than the task's board. | Pick a milestone from the board's project. |
| `move_board_state_invalid` | 400 | A move to another board named a target state (or state map) that does not fit the target board. | Send a `state` of the target board, or a valid `state_map`. |
| `notification_routes_limit_reached` | 400 | The organization already has 10 channel routes (`extra.limit`). | Delete or reuse a route. |
| `participant_cannot_access_board` | 400 | The person you set as owner or participant cannot see the board. | Give them access to the board first, or pick someone from `…/mentionables/`. |
| `platform_not_connected` | 400 | The organization has no chat platform to post to or search channels in. | Connect Slack, Microsoft Teams, Discord or Google Chat first. |
| `reaction_invalid_emoji` | 400 | The reaction must be a single emoji (at most 32 characters). | Send one emoji. |
| `reaction_limit_reached` | 400 | You already hold the maximum number of different emojis on this comment or update (`extra.limit`). | Remove one of your reactions first. |
| `report_schedules_limit_reached` | 400 | The organization already has 10 scheduled reports (`extra.limit`). | Delete or reuse a schedule. |
| `route_scope_not_org_visible` | 400 | A route or report scope names a members-only board or project (`extra.uuids`). Channels only receive what the whole workspace can see. | Remove those uuids from the scope. |
| `search_query_too_long` | 400 | The search text is longer than 256 characters. | Shorten the query. |
| `search_query_too_short` | 400 | The search text is shorter than 2 characters. | Send at least 2 characters. |
| `state_not_on_board` | 400 | The state you named does not belong to the task's board. | Use a state uuid from `GET …/boards/{board_id}/states/`. |
| `states_reorder_invalid` | 400 | The reorder list does not name every live column exactly once. | Send every live state uuid once, in order. |
| `subtask_cross_board` | 400 | A sub-task must live on the same board as its parent. Also returned when moving a task to another board while it still has live sub-tasks, or while it is itself a sub-task of a task on the source board. | Detach or move the sub-tasks first, or keep the task on its parent's board. |
| `subtask_depth_exceeded` | 400 | Sub-tasks nest one level only. | Attach it to a top-level task. |
| `too_many_filter_values` | 400 | A repeatable filter has more than 50 values (`extra.limit` gives the exact number). | Send fewer values per request. |
| `too_many_items` | 400 | The bulk call has more than 100 items. | Split it into calls of up to 100 items. |
| `unknown_field` | 400 | A body field the endpoint does not accept (`extra.parameter` names it). It is refused, never dropped. | Remove the field. |
| `unknown_notification_kind` | 400 | A notification kind that is not in the catalogue (`extra.parameter: "kind"`). | Use a `key` from `GET /v1/plan/notifications/catalog/`; personal kinds for your switches, organization kinds for a route. |
| `update_body_too_long` | 400 | The project update is longer than 20,000 characters (`extra.max_length`). | Shorten the update. |
| `version_precondition_ambiguous` | 400 | `If-Match` and the body field `version` were both sent, with different values. | Send one of them. |
| `view_limit_reached` | 400 | You already have 20 personal saved views on this board, the limit. | Delete a view before saving another. |

<h3 id="status-401">401 Unauthorized: the credential is missing or not valid</h3>

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `api_key_owner_inactive` | 401 | The API key's owner has been deactivated. | Create a key for an active person. |
| `credential_absent` | 401 | No credential was sent. | Send `Authorization: Bearer …` or `X-API-KEY`. |
| `credential_expired` | 401 | The credential has expired. | Sign in again (`dailybot login`) or use a current key. |
| `credential_malformed` | 401 | The credential could not be read. | Check the header name and value. |
| `invalid_credentials` | 401 | The key or token does not exist. | Use a valid credential. |
| `plan_free_api_keys_forbidden` | 401 | API keys are not available on the free plan. | Use a CLI user token, or upgrade the plan. |
| `plan_missing_core_api_integrations` | 401 | The organization's plan does not include API access. | Upgrade to a plan with API access. |

<h3 id="status-402">402 Payment Required: Plan is not enabled, or a plan ceiling is reached</h3>

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `plan_upgrade_required` | 402 | Plan is not enabled for your organization yet. Expected during the Beta. (A free-plan CLI sign-in gets `403` with the same code.) | Write to support@dailybot.com to join the Beta. `GET /v1/plan/entitlements/` shows the state. |
| `task_boards_limit_reached` | 402 | The plan's board ceiling is reached (the free plan includes up to 3 boards). | Archive a board to free a slot, or upgrade. |
| `task_projects_limit_reached` | 402 | The plan's project ceiling is reached (the free plan includes 1 project). | Archive a project to free a slot, or upgrade. |

<h3 id="status-403">403 Forbidden: you are signed in but not allowed</h3>

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `attachment_delete_forbidden` | 403 | Only the person who uploaded the attachment or an organization admin can remove it; on a comment, the comment's author can too. | Ask the uploader, the comment's author or an organization admin. |
| `comment_not_author` | 403 | Only the author can edit or delete this comment, or attach files to it. | Ask the author. |
| `guest_not_allowed` | 403 | Guest accounts cannot use Plan. | Use a member account. |
| `insufficient_scope` | 403 | The credential lacks the scope this endpoint needs (`tasks:read`, `tasks:write` or `tasks:admin`). A non-guest member's login session and personal API key can call every endpoint, so this means the key row's explicit Plan scopes do not cover the endpoint, or an agent or organization key called an endpoint that needs a person. | Use a personal API key or a login session, or add the missing scope to the key. See [Authentication for Plan](/developers/plan/authentication#scopes). |
| `task_archived` | 403 | An archived task cannot be duplicated. | Restore the task first, then duplicate it. |
| `update_not_author` | 403 | Only the author of a project update can edit it or attach files to it; the author or an organization admin can delete it. | Ask the author, or an organization admin for a delete. |
| `view_visibility_forbidden` | 403 | Only a board manager can make a view `shared` or `board_default`, or edit or delete one. | Keep the view `personal`, or ask a board manager. |

<h3 id="status-404">404 Not Found: the object does not exist or is not visible to you</h3>

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `not_found` | 404 | The object does not exist, or it is not visible to you (for example a `members` project or board without a grant). Both cases return the same body on purpose. | Check the identifier. Treat this as **not visible**, never as “not allowed”. |

<h3 id="status-409">409 Conflict: the request conflicts with the current state</h3>

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `attachment_not_ready` | 409 | The upload was never completed or confirmed. | Finish the upload and call `…/confirm/`. |
| `board_not_initialized` | 409 | The board has no column the operation needs: no default column to create a task in, or no `done` column to close a task into. | Add the missing column to the board. |
| `duplicate_board_key` | 409 | Another board already uses this key (retired keys stay reserved). | Choose another key. |
| `goal_name_conflict` | 409 | A live goal already has this name. | Rename one of the goals. |
| `idempotency_in_progress` | 409 | A call with the same `Idempotency-Key` is still running (up to 120 seconds). | Wait and retry with the same key. |
| `idempotency_key_payload_mismatch` | 409 | The `Idempotency-Key` was already used with a different body. | Use a new key for a new intent. |
| `identifier_allocation_failed` | 409 | A task key (`KEY-n`) could not be allocated because several tasks were being created at once. | Retry the request with the same `Idempotency-Key`. |
| `label_in_use` | 409 | The label is still on tasks, so it cannot be deleted. | Archive it with `PATCH {"is_archived": true}` instead. |
| `last_grant_cannot_be_removed` | 409 | This is the last member of a members-only board or project. | Add another member first, or make it organization-visible. |
| `project_name_conflict` | 409 | A project in the workspace, live or archived, already has this name. | Choose another name, or rename the other project. |
| `rank_neighbor_missing` | 409 | The `after` / `before` task moved away. The response names the column's current head and tail. | Retry with a current neighbour. |
| `relation_cycle` | 409 | The link would create a cycle. | Link the tasks the other way, or not at all. |
| `relation_exists` | 409 | The two tasks are already linked this way. | Nothing to do. |
| `state_in_use` | 409 | Live tasks still sit in the state (column), or a restore targets an archived state. | Send `migrate_to`, or restore to another state. |
| `version_conflict` | 409 | The task changed since you loaded it. `extra.current_version` has the new version. | Re-read, reconcile and retry with the new version. |

<h3 id="status-412">412, 422 and 428: preconditions and placement</h3>

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `column_too_large` | 422 | The target column has reached its limit of 5,000 tasks. | Move or archive tasks, or split the board. |
| `precondition_failed` | 412 | The `If-Match` validator on a saved-view write is stale. | Read the views again and retry with the new `ETag`. |
| `precondition_required` | 428 | A saved-view write was sent without `If-Match`. | Send the `ETag` from your last read. |

<h3 id="status-5xx">501 and 503: not available right now</h3>

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `not_implemented` | 501 | The operation is not available yet. For example, setting `milestone` when creating a task: set it with `PATCH` after creating the task. | Use the documented alternative, or check the API changelog. |
| `attachment_storage_unavailable` | 503 | File storage is temporarily unavailable. | Retry later. |
| `feature_temporarily_read_only` | 503 | Plan is temporarily read-only during an incident. **Reads keep working**, so you can always export your work. This is not the same as `402`. | Retry writes later; keep reading as usual. |

<h2 id="rate-limits">429 Too Many Requests</h2>

Past a rate limit (reads 120, writes 60, bulk 30, delta feed 240 per minute per actor), the API answers `429` with a `Retry-After` header. Wait that many seconds before retrying. See [Conventions for Plan](/developers/plan/conventions#rate-limits).

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `throttled` | 429 | A rate ceiling for this actor was hit. `extra.retry_after` and the `Retry-After` header say how many seconds to wait. | Wait that long, then retry. |

---

## Developer portal navigation

**Getting Started**

- [Overview](/developers)
- [Quick start](/developers/getting-started)
- [Authentication](/developers/authentication)

**API Reference**

- [API Overview](/developers/api)
- [Users](/developers/api/users)
- [Organization](/developers/api/organization)
- [Teams](/developers/api/teams)
- [Invitations](/developers/api/invitations)
- [Check-ins](/developers/api/check-ins)
- [Forms](/developers/api/forms)
- [Labels](/developers/api/labels)
- [Report channels](/developers/api/report-channels)
- [Templates](/developers/api/templates)
- [Kudos](/developers/api/kudos)
- [Mood tracking](/developers/api/mood)
- [Important dates](/developers/api/important-dates)
- [Messaging](/developers/api/messaging)
- [Automations](/developers/api/workflows)
- [Webhooks](/developers/api/webhooks)
- [Commands platform](/developers/api/commands-platform)
- [Agents](/developers/api/agents)
- [OAuth2](/developers/api/oauth2)
- [Integrations](/developers/api/integrations)
- [CLI](/developers/api/cli)
- [Plan · Projects](/developers/api/plan-projects)
- [Plan · Goals](/developers/api/plan-goals)
- [Plan · Boards](/developers/api/plan-boards)
- [Plan · Tasks](/developers/api/plan-tasks)
- [Plan · Comments & files](/developers/api/plan-collaboration)
- [Plan · Home & search](/developers/api/plan-home)
- [Plan · Notifications & reports](/developers/api/plan-notifications)

**Dailybot Plan**

- [Overview](/developers/plan)
- [Concepts](/developers/plan/concepts)
- [Quickstart](/developers/plan/quickstart)
- [Authentication & scopes](/developers/plan/authentication)
- [Agents on Plan](/developers/plan/agents)
- [Conventions](/developers/plan/conventions)
- [Errors](/developers/plan/errors) (this page)
- [CLI for Plan](/developers/plan/cli)
- [Agent skill](/developers/plan/agent-skill)
- [Recipe: live board](/developers/plan/recipes/board-live-updates)
- [Recipe: home in one request](/developers/plan/recipes/home-in-one-request)
- [Recipe: bulk create](/developers/plan/recipes/bulk-create)
- [Recipe: move on PR merge](/developers/plan/recipes/move-on-pr-merge)
- [Recipe: goal progress](/developers/plan/recipes/goal-progress)
- [Recipe: webhooks](/developers/plan/recipes/webhooks)

**API guides**

- [Errors & Status Codes](/developers/errors)
- [Rate Limits](/developers/rate-limits)
- [Conventions](/developers/conventions)
- [API Changelog](/developers/api-changelog)
- [Recipes](/developers/recipes)

**Developer Features**

- [Custom commands](/developers/custom-commands)
- [Serverless commands](/developers/serverless)
- [Webhooks & events](/developers/webhooks)
- [Automation API trigger](/developers/workflow-trigger)
- [Activity API](/developers/activity-api)

**CLI**

- [Overview](/developers/cli)
- [Authentication](/developers/cli-authentication)
- [Command reference](/developers/cli-reference)
- [CI/CD recipes](/developers/cli-ci-cd)
- [Configuration](/developers/cli-configuration)
- [Troubleshooting](/developers/cli-troubleshooting)

**Agent Skill**

- [Overview](/developers/agent-skill)
- [Skills catalog](/skills)

---

## Site navigation

**Product:**
- [Home](/)
- [Product](/product)
- [Pricing](/pricing)
- [Enterprise](/enterprise)
- [Integrations](/integrations)
- [Templates](/templates)

**Resources:**
- [Blog](/blog)
- [Academy](/academy)
- [Changelog](/changelog)
- [Help Center](/help)
- [Developers](/developers)
- [Agents](/agents)

**Company:**
- [About](/about)
- [Careers](/careers)
- [Security](/security)
- [Contact Sales](/demo)

**Connect:**
- [LinkedIn](https://www.linkedin.com/company/dailybot/)
- [X/Twitter](https://twitter.com/dailybot)
- [GitHub](https://github.com/Dailybot-Inc)
- [YouTube](https://www.youtube.com/channel/UC3uM9V52vwX7e3vQpCc4qvA)

