Errors

Error envelopes, HTTP status codes, the full error-code list, and how to recover.

ClawLink distinguishes between an action that couldn't start (blocked — you can usually fix it and retry) and one that ran and failed (failed). Both are reported in a normalized shape so you can branch programmatically.

Error envelopes

Which envelope you get depends on the endpoint.

Canonical endpoints

POST /api/executions, GET /api/executions/{id}, and the discovery endpoints return an execution summary. On a problem, status is "blocked" or "failed":

{
  "execution_id": null,
  "status": "blocked",
  "integration_id": "gmail",
  "action_id": "send_email",
  "display": { "title": "Execution blocked", "summary": "Gmail isn't connected yet." },
  "error_code": "integration_not_connected",
  "message": "Gmail isn't connected yet.",
  "recommended_next_action": {
    "tool": "clawlink.connect_app",
    "input": { "integration_id": "gmail" }
  }
}
  • blocked → the action never ran (policy, missing/expired connection, ambiguous connection). execution_id is null. Fix the cause and retry.
  • failed → the action ran and errored. execution_id is set.
  • recommended_next_action appears when the fix is to connect or re-auth an app.

Tool endpoint

POST /api/tools/{tool_name}/execute returns the raw payload with ok: false and a structured error, plus a canonical block mirroring the shape above:

{
  "ok": false,
  "toolName": "gmail_send_email",
  "integration": "gmail",
  "error": {
    "type": "validation",
    "code": "invalid_arguments",
    "message": "Missing required field: subject",
    "retryable": false
  },
  "canonical": { "status": "failed", "error_code": "validation_error", "message": "Missing required field: subject" }
}

error.retryable tells you whether retrying the same request could succeed (e.g. a transient rate_limit or network error).

Simple guard errors

Malformed requests and auth failures (before any execution) return a bare object:

{ "error": "integration_id, action_id, and object input are required" }

HTTP status codes

StatusMeaning
200status: "succeeded"
400Missing integration_id, action_id, or object input
401Missing/invalid API key
409status: "blocked" (e.g. confirmation required, not connected)
500status: "failed", or an unexpected server error

Error codes

error_code (canonical) values and how to recover:

error_codeMeaningWhat to do
unauthorizedInvalid API key, or provider auth rejectedCheck the key; the app may need re-auth
forbiddenConnected account lacks the required scopesReconnect with the needed permissions
integration_not_foundUnknown integration_idCheck the slug via /api/integrations
action_not_foundUnknown action_id for that integrationCheck via /api/actions?integration_id=…
integration_not_connectedApp isn't connectedConnect it in the dashboard (recommended_next_action)
reauth_requiredConnection expired or revokedReconnect the app (recommended_next_action with force_reconnect)
validation_errorBad or missing argumentsFix input; check the action's input_schema
policy_blockedWrite needs confirmation, or an ambiguous connectionResend with confirm: true, or disambiguate the connection
rate_limitedProvider rate limit hitBack off and retry; honor Retry-After
timeoutProvider took too longRetry
unsupported_operationProvider/operation unavailableDon't retry as-is
execution_failedAction ran and failedInspect message / hint

When present, the hint field contains concrete recovery guidance — for example, the upload-and-retry curl for a missing local file (see File uploads). Surface it; it's written to be actionable.

Recovering connection problems

integration_not_connected and reauth_required come with a recommended_next_action pointing at the connect flow:

{
  "recommended_next_action": {
    "tool": "clawlink.connect_app",
    "input": { "integration_id": "gmail", "force_reconnect": true }
  }
}

Connecting and re-authing apps is a hosted, browser-based flow done from the dashboard (Connections). Once the app is healthy, retry the original request unchanged.

On this page