Errors
Every v3 error is an RFC 7807 problem-details body. At
https://openapi.niftypm.com/api/v3 every one of them is served as
application/json, the 429 a rate limiter raises included — see
Rate limits:
Code
Branch on code, never on detail (wording can change). Quote requestId when you contact support. Validation errors add errors: [{ field, code, message }]; expand_unknown_relation adds available: [...]. Extra fields like these sit at the top level of the body, not nested under a meta key. The legacy v1 API uses a different shape, { "message": "...", "code": 401 }, and OAuth endpoints use RFC 6749 { "error", "error_description" }.
validation_failed
HTTP 400. The request body failed validation — a missing required field, wrong type, or out-of-range value.
Fix: Check errors[] for the specific field(s) and resend with corrected values.
cursor_invalid
HTTP 400. The ?cursor= value on a paginated LIST isn't a cursor this endpoint issued — malformed, expired, or copied from a different resource or sort.
Fix: Drop the cursor and start pagination over, or use the nextCursor from the endpoint's own most recent response.
cursor_sort_mismatch
HTTP 400. A paginated request supplied both ?cursor= and ?sort=, and the sort doesn't match the one the cursor was minted under.
Fix: Keep the same sort value across every page of a paginated walk, or drop the cursor and restart.
pagination_param_unknown
HTTP 400. A LIST request included a pagination query parameter the endpoint doesn't recognize.
Fix: Remove the unrecognized parameter; valid pagination params are cursor, limit, sort.
sort_field_invalid
HTTP 400. ?sort= named a field the resource doesn't allow sorting by.
Fix: Use one of the resource's allowed sort fields — field names the rejected field and resource the resource it was requested on.
resource_unknown
HTTP 400. The resource name in the URL path (e.g. /v3/<name>) does not match any v3 resource.
Fix: Check the resource name against the v3 API reference for a typo.
resource_misconfigured
HTTP 400. The server could not process the request.
Fix: Retrying is unlikely to help — report it with the requestId.
search_query_missing
HTTP 400. A search endpoint was called without a ?q= parameter.
Fix: Pass a non-empty q.
search_query_too_short
HTTP 400. ?q= is under 3 characters.
Fix: Use 3 or more characters.
search_query_too_long
HTTP 400. ?q= exceeds 200 characters.
Fix: Shorten the query.
search_query_invalid
HTTP 400. ?q= contains a URL, script tag, HTML, or email address — a spam-shield rejection.
Fix: Strip the flagged content; reason names which check failed (url | script | html | email).
search_timed_out
HTTP 400. The search took too long to complete.
Fix: Narrow the search (e.g. scope to a project) instead of searching the whole workspace; retrying the identical query will likely time out again.
identity_rejected
HTTP 400. The authenticated identity's type (human, agent, system, OAuth, etc.) isn't allowed to perform this specific operation.
Fix: Use a credential of the identity type the operation requires — detail names it.
empty_update
HTTP 400. A PATCH body has zero fields to update.
Fix: Include at least one field to change.
project_not_specified
HTTP 400. A project-scoped resource was created or listed without identifying a project.
Fix: Pass projectId in the request body (create) or ?projectId= (list).
accessible_project_ids_exceeded
HTTP 400. A workspace-scope LIST (no ?projectId= filter) was requested by a caller with access to more than 1000 projects, exceeding the fan-out cap.
Fix: Narrow the request with ?projectId=<id>.
milestone_dependency_wrong_project
HTTP 400. A task's dependencyId references a task in a different project than the task being created or updated.
Fix: Use a dependency task from the same project.
milestone_hiddenfor_roles_not_in_team
HTTP 400. A milestone's hiddenFor array names role IDs that don't belong to the team.
Fix: Use role IDs from GET /v3/roles for this team.
favorite_folder_invalid
HTTP 400. favoriteFolderId doesn't reference a folder the caller owns.
Fix: Use a folder ID returned by the caller's own GET /v3/favorite-folders, or omit the field.
expand_too_deep
HTTP 400. ?expand= requested a relation chain deeper than the endpoint's depth limit.
Fix: Shorten the expand path — max names the limit, depth what you asked for, and path the offending entry.
expand_cycle_detected
HTTP 400. An ?expand= path revisits a resource already visited earlier in the same chain.
Fix: Remove the relation that creates the cycle.
expand_unknown_relation
HTTP 400. An ?expand= segment names a relation the resource doesn't have — usually a typo.
Fix: Check available for the valid relation names on this resource.
expand_budget_exceeded
HTTP 400. The total rows materialized by ?expand= across the whole request exceeded the per-request budget — protects against fan-out shapes like ?expand=subtasks.subtasks.subtasks.
Fix: Drop the relation named in relation and re-issue with a narrower expand; budget names the per-request row budget.
invalid_field_selector
HTTP 400. ?fields[resource]= names a field the resource doesn't have.
Fix: Check the field name against the resource's schema.
invalid_query_param
HTTP 400. A known query parameter was given a value outside its allowed set (e.g. ?include_trashed=maybe).
Fix: Use one of the values in allowed for the parameter named in name.
move_target_milestone_mismatch
HTTP 400. A cross-project task move (PATCH task.projectId) also set milestoneId to a milestone that lives in a different project than the new target.
Fix: Pass a milestoneId from the target project, or omit it and let the move default one.
move_target_taskgroup_mismatch
HTTP 400. Same as move_target_milestone_mismatch but for taskGroupId (v3's name for the status column).
Fix: Pass a taskGroupId from the target project, or omit it.
move_target_no_default_milestone
HTTP 400. A cross-project task move omitted milestoneId and the target project has no non-archived milestone to default to.
Fix: Create a milestone in the target project first, or pass an explicit milestoneId.
move_target_no_default_taskgroup
HTTP 400. Same as move_target_no_default_milestone but for the target project's status column.
Fix: Create a status in the target project first, or pass an explicit taskGroupId.
task_no_default_status
HTTP 400. A task is being created in a project that has no active status to default the task into.
Fix: Create a status in the project first, or pass an explicit taskGroupId.
move_subtask_must_move_with_parent
HTTP 400. task.projectId was PATCHed directly on a subtask.
Fix: Move the parent task instead (the whole subtree moves with it), or clear parentTaskId first to promote the subtask to a root task, then move it.
task_subtask_chain_too_deep
HTTP 400. A cross-project task move's subtree (root + descendants) exceeded 200 nodes; the transaction rolled back atomically rather than landing a half-moved tree.
Fix: Split the move into smaller per-subtree PATCH calls.
task_dependency_incomplete
HTTP 400. completed: true was PATCHed on a task whose dependency task isn't complete yet.
Fix: Complete the dependency task first, or have a workspace admin enable the team's "Complete Dependant Tasks" setting.
bulk_too_large
HTTP 400. A bulk write named more than 150 items.
Fix: Split the request into batches of 150 or fewer.
batch_empty
HTTP 400. An M2M sub-resource request (e.g. POST /v3/files/:id/labels) sent a missing or empty ids array.
Fix: Pass a non-empty ids: string[].
batch_too_large
HTTP 400. An M2M sub-resource request's ids array exceeded the endpoint's max.
Fix: Split into smaller batches — max names the limit and received what you sent.
m2m_relation_unknown
HTTP 400. An M2M sub-resource request named a relation the parent resource doesn't declare — usually a typo'd relation segment.
Fix: Use one of the relation names the error body lists for this resource.
m2m_target_not_found
HTTP 404. One or more ids in an M2M sub-resource request don't exist, are soft-deleted, or belong to a different workspace. The whole operation is rejected rather than partially applied.
Fix: Drop the IDs listed in missing and retry.
m2m_not_supported
HTTP 501. This relation is not available on this resource.
Fix: Retrying won't help; report it.
unauthorized
HTTP 401. The request has no valid authentication credential — no bearer token, or the header is missing or malformed.
Fix: Send Authorization: Bearer <token> with a valid Personal Access Token or OAuth access token.
invalid_token
HTTP 401. The bearer token isn't found, was revoked, or is otherwise invalid.
Fix: Mint a new Personal Access Token or re-run the OAuth flow.
token_expired
HTTP 401. The bearer token's expiresAt has passed.
Fix: Mint a new token.
token_owner_inactive
HTTP 401. The token's owning team member has been deactivated, or the owning user account has been deleted.
Fix: The token can't be reactivated — have an active member mint a new one.
pat_cap_reached
HTTP 400. Creating a new Personal Access Token would exceed the 20-active-PAT-per-user cap.
Fix: Revoke an existing token first (DELETE /personal-access-tokens/{id}), then create the new one.
cannot_broaden_scope
HTTP 400. Updating a PAT tried to add a scope it didn't already have.
Fix: Revoke the token and issue a new one with the broader scope set instead of updating in place.
cannot_shorten_expiry
HTTP 400. Updating a PAT tried to set expiresAt earlier than its current value.
Fix: Use revoke instead of shortening expiry.
cannot_create_empty_token
HTTP 400. The scopes requested for a new PAT don't intersect with the creating user's actual role permissions — the token would be able to do nothing.
Fix: Request only scopes the user's role actually grants.
permission_denied
HTTP 403. The authenticated identity is missing one or more permissions the operation requires.
Fix: Check missingPermissions in the response and have a workspace admin grant them, or use a credential with the right role/scopes.
project_access_denied
HTTP 403. The authenticated identity doesn't have access to the specific project the request targets.
Fix: Use a credential belonging to a team member with access to that project.
default_label_locked
HTTP 403. The request tried to rename or delete a system default label (e.g. the archived-status label).
Fix: Default labels can't be mutated — create a new label instead.
default_role_locked
HTTP 403. The request tried to rename, re-permission, or delete a system role (owner, manager, regular, client).
Fix: System roles are fixed — create a custom role instead.
permission_exceeds_caller_grant
HTTP 403. A caller tried to set a role's permissions to include a permission they don't themselves currently hold.
Fix: Only grant permissions the acting identity already has.
resource_not_found
HTTP 404. The requested resource ID doesn't exist, is soft-deleted, or isn't accessible to the caller.
Fix: Check the ID and the caller's access to that resource.
conflict
HTTP 409. The generic catch-all for a state collision that doesn't have its own dedicated code — typically a business-rule invariant the current row state violates.
Fix: Re-read the resource's current state and adjust the request accordingly; detail names the specific conflict.
duplicate_label
HTTP 409. A create or rename set a label name that already exists (case aside) among the team's active labels.
Fix: Use a different name.
duplicate_role
HTTP 409. A create or rename set a role name that already exists in the team.
Fix: Use a different name.
role_in_use
HTTP 409. A role delete was requested while the role is still assigned to one or more active team members.
Fix: Reassign those members to a different role first.
regular_role_missing
HTTP 409. A role delete needs to reassign its former (removed) holders to the team's "regular" role, but the team has none.
Fix: Create a regular role in the team, or leave this role in place.
stale_write
HTTP 409. An update included expectedUpdatedAt and the row's actual updated_at no longer matches — another writer committed after the read this update was based on.
Fix: Re-read the resource, re-derive your change from the current values, and retry with the fresh updatedAt. Do not reuse the value in detail.
idempotency_key_reuse
HTTP 422. An Idempotency-Key was reused with a request body whose content fingerprint differs from the first use of that key.
Fix: Use a fresh Idempotency-Key for the new body.
idempotency_in_progress
HTTP 409. A retry with the same Idempotency-Key arrived while the first request with that key was still being processed.
Fix: Back off briefly and retry — the first request's result will apply.
name_contains_url
HTTP 400. A free-text name field (workspace, project, portfolio, label, etc.) contains a URL.
Fix: Remove the URL from the name.
name_contains_email
HTTP 400. A free-text name field contains an email address.
Fix: Remove the email address from the name.
name_contains_html
HTTP 400. A free-text name field contains HTML markup.
Fix: Remove the markup — use plain text.
name_contains_script
HTTP 400. A free-text name field contains script-like markup.
Fix: Remove the script-like content.
team_storage_quota_exceeded
HTTP 413. Uploading a file would put the team over its storage quota (storage_per_user × billable members, in GiB).
Fix: Free up space or upgrade the plan — usage/limit/requested in the body show the numbers.
rate_limited
HTTP 429. The caller exceeded the API rate limit.
Fix: Back off and retry after retryAfter seconds (also in the Retry-After header); scope names which limit you hit.
free_plan_write_cap_exceeded
HTTP 429. A free-plan team's programmatic caller (agent, or a PAT/OAuth-bearer human) hit the per-team, per-resource, per-day create cap.
Fix: Wait for the daily UTC reset, or upgrade the plan — the cap doesn't apply to paid teams. limit, used and resource describe the cap you hit.
quota_exceeded
HTTP 429. The team has spent its monthly allowance for a metered dimension (automation runs, API/MCP calls, AI generations, form responses).
Fix: Wait until resetsAt, or have the billing owner raise the plan's limit for dimension. The same numbers arrive as the X-Quota-Limit, X-Quota-Remaining and X-Quota-Reset headers.
not_implemented
HTTP 501. This operation is not available on this resource.
Fix: This operation isn't available for this resource — check the API reference for what it does support.
create_not_durable
HTTP 503. The create could not be confirmed.
Fix: Retry with the same Idempotency-Key; it's safe either way — a true miss gets a fresh create, a false alarm replays the already-committed result.
internal_error
HTTP 500. The fallback for an unexpected server-side error that doesn't map to any other code.
Fix: Retry once; if it persists, report it with the requestId.
actor_resolution_failed
HTTP 500. The server could not resolve the acting identity.
Fix: Not caller-fixable — report it with the requestId.
response_schema_violation
HTTP 500. The write was not applied.
Fix: Retry once with the same Idempotency-Key; if it persists, report it with the requestId.
route_not_found
HTTP 404. No v3 route matches the method and path.
Fix: Check the method and the path against the v3 API reference.