Errors
Error format
REST errors use application/problem+json:
{
"type": "about:blank",
"title": "Forbidden",
"status": 403,
"code": "insufficient_scope",
"detail": "This token doesn't have members:read.",
"instance": "urn:uuid:99999999-9999-4999-8999-999999999991",
"request_id": "99999999-9999-4999-8999-999999999991",
"error": {
"code": "missing_permission",
"message": "This token doesn't have members:read.",
"fix": "Edit the token's permissions in Settings → API connections.",
"docs_url": "https://api.fieldtask.example/public/docs/"
}
}
- Branch on
code: it's the stable, machine-readable value listed below. erroris meant for people: a message, a suggested fix and a documentation link.error.codeusually equalscode; for a missing permission,codeisinsufficient_scopeanderror.codeismissing_permission.- Errors never repeat the values you sent, and validation errors don't name the failing field.
- Event feed errors that require you to start over also include
"resync_required": true.
Every response, successful or not, has an X-Request-ID header, and errors repeat it as request_id.
MCP errors
MCP tool calls that fail return a tool result with isError: true and the same error object (code, message, fix, docs_url, plus request_id, and retry_after in seconds when you should wait). Problems with the MCP connection itself, such as an expired sign-in, are reported by the MCP protocol instead, and the client asks you to sign in again.
Error codes
Each endpoint's page lists the codes it can return. This is the complete list.
| Status | code | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_cursor | The cursor is malformed, was changed, or belongs to a different query, connection or page size. | Use `next_page_url` or the cursor exactly as returned, with the same query. To change the query, start again without a cursor. |
| 400 | invalid_json | The body isn't one valid JSON value, repeats a property name, uses `NaN`/`Infinity` or nests deeper than 10 levels. | Send a single JSON object encoded as UTF-8. |
| 400 | invalid_operation_key | `Idempotency-Key` isn't 16–128 printable ASCII characters. | Use a UUID or another 16–128 character key without spaces at either end. |
| 400 | invalid_query | The query string has an unknown, repeated or invalid parameter. | Send only the documented query parameters, each once. |
| 401 | invalid_token | The bearer token is missing, malformed, expired, revoked or issued for a different resource (for example an MCP sign-in). | Send a current REST API token or REST OAuth access token as `Authorization: Bearer …`. |
| 403 | api_access_not_enabled | FieldTask hasn't enabled API access for this organization, or has disabled it. | An owner or admin requests access in **Settings → API connections**. |
| 403 | insufficient_scope | The connection lacks a permission this request needs. `error.code` is `missing_permission`. | Add the permission named in `error.message` to the connection. |
| 403 | operation_forbidden | The connection's access changed while the request was processed, or the result would include data the connection can no longer read. | Check the connection's permissions, then retry. Retry creates with the same key and body. |
| 404 | resource_not_found | The record doesn't exist or isn't visible to this connection, the feature isn't available in this environment, or the URL is wrong. | Check the ID, the API origin and the path (no trailing slash). |
| 405 | method_not_allowed | This path doesn't accept the HTTP method, or the create isn't enabled in this environment. The `Allow` header lists the methods that are. | Use a method listed in `Allow`. |
| 409 | access_context_changed | The connection's permissions, enrollment or resource selection changed since this cursor was issued. `resync_required` is `true`. | Get a new cursor with `after=now`, then rebuild the affected local data from the list endpoints. |
| 409 | external_reference_conflict | Another record created through this client application already uses this `external_reference`. Nothing was updated. | Find the existing record with `?external_reference=…`. Use a new reference only for a genuinely new record. |
| 409 | idempotency_key_reused | This key was already used with a different body. | Resend the original body with this key, or use a new key for a different record. |
| 409 | idempotency_window_expired | This key was used more than seven days ago. It can't be replayed or reused. This doesn't mean the original request failed. | Reconcile using your saved record ID before creating anything new. |
| 409 | operation_in_progress | A request with the same key is still being processed. | Wait for `Retry-After` seconds, then retry with the same key and body. |
| 410 | history_expired | The cursor points to changes older than the feed keeps. `resync_required` is `true`. | Get a new cursor with `after=now`, then rebuild your local data from the list endpoints. |
| 410 | operation_result_expired | The operation result is older than seven days and is no longer kept. This doesn't mean the create failed. | Reconcile using the record ID you saved from the original response. |
| 410 | resource_gone | The record created by this operation no longer exists. | Don't create it again automatically. Check in FieldTask whether it was removed on purpose. |
| 413 | payload_too_large | The body is larger than 256 KiB. | Send a smaller body. |
| 415 | unsupported_media_type | `Content-Type` isn't `application/json`, or the body is compressed. | Send an uncompressed body with `Content-Type: application/json`. |
| 422 | report_too_large | The selected date range contains too many entries to page through. | Use a shorter date range. A smaller `page_size` doesn't help. |
| 422 | validation_failed | A field is missing, unknown or invalid, a referenced record isn't eligible, or the input needs a feature that isn't enabled. | Check the request against the field descriptions. The response doesn't name the field. |
| 429 | daily_quota_exceeded | The organization or connection has used its daily allowance for this kind of request. Allowances reset at 00:00 UTC. | Wait for `Retry-After` seconds, or check remaining allowance in **Settings → API connections**. |
| 429 | rate_limit_exceeded | Too many requests in the current minute, or too many concurrent requests, for the organization or connection. | Wait for `Retry-After` seconds, then retry. |
| 503 | sync_unavailable | The change feed couldn't be read right now. | Retry with backoff using the same cursor. |
| 503 | temporarily_unavailable | The service couldn't complete the request. | Retry with exponential backoff. Retry creates with the same key and body. |
The OAuth token endpoint returns standard OAuth errors (invalid_client, invalid_target and so on) instead of this format.
Retrying
| Status | Retry? |
|---|---|
400, 401, 403, 404, 405, 413, 415, 422 | No. Fix the request, credential or permissions first. |
409 operation_in_progress, 429 | Yes, after Retry-After seconds. |
503, timeouts, connection errors | Yes, with exponential backoff. |
Always retry a create with the same idempotency key and body.
Contacting support
Include the time, the HTTP method and path, the status and code, and the X-Request-ID. Never include tokens, client secrets or invitation links.