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.
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 [email protected].
Every Plan error answers with an HTTP status and a JSON body. Branch on the machine-readable code, never on the human-readable detail:
{
"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:
{ "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.
During the Beta, 402 is expected
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 [email protected] to join. GET /v1/plan/entitlements/ is the one Plan endpoint that never answers 402, so you can check the state first.
402 and 503 mean different things
| 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.
404 never reveals what exists
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.
All codes
400 Bad Request: the request could not be accepted as sent
| 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. |
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. |
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. |
401 Unauthorized: the credential is missing or not valid
| 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. |
402 Payment Required: Plan is not enabled, or a plan ceiling is reached
| 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 [email protected] 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. |
403 Forbidden: you are signed in but not allowed
| 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. |
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. |
404 Not Found: the object does not exist or is not visible to you
| 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”. |
409 Conflict: the request conflicts with the current state
| 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. |
412, 422 and 428: preconditions and placement
| 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. |
501 and 503: not available right now
| 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. |
429 Too Many Requests
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.
| 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. |