Error taxonomy
Every Agent API error has the same shape:
{
"error": {
"code": "validation_failed",
"message": "handle is required.",
"suggested_action": "fetch_pipeline",
"suggested_endpoint": "GET /pipelines/{id}"
}
}
| Field | Detail |
|---|---|
error.code | Always present. Stable identifier (closed list below). |
error.message | Always present. Human-readable; informational, not programmatic — code against code. |
error.suggested_action | Optional. Agent-actionable next step when one is unambiguous (e.g. connect_account, fetch_artifact). |
error.suggested_endpoint | Optional. The endpoint to call to take suggested_action. |
X-Request-Idlives in the response header, not in the body. Correlate by that header when reporting issues.
Closed list of codes
| HTTP | code | When |
|---|---|---|
400 | bad_request | Malformed JSON, invalid cursor, missing required fields outside the validation set. |
401 | unauthorized | Authorization header missing, token wrong, or Whet Desktop has not minted an agent token yet (open the app once to provision). |
403 | forbidden | Token is valid but the workspace state forbids the action (e.g. publishing while still in draft). |
404 | not_found | Resource doesn't exist in the workspace bound to this token. |
409 | state_conflict | Resource isn't in a valid state for the operation (e.g. publish_artifact on a discarded artifact). |
422 | validation_failed | Body shape failed validation. message names the field. |
424 | credential_missing | An adapter credential the operation needs is absent. suggested_action: connect_account with the relevant platform identifier. |
424 | credential_dead | The stored credential exists but the probe failed (expired session, revoked token). |
429 | rate_limited | Per-token quota exceeded. Retry-After carries the wait. |
503 | backend_unavailable | The internal whet-app ↔ backend channel can't reach the backend. Check BACKEND_BASE_URL and that the backend container is healthy. |
5xx | internal_error | Unhandled exception. Always carries X-Request-Id. |
Suggested-action map
When an error is recoverable without a human in the loop, the response embeds a suggested_action. The agent can act on it directly:
suggested_action | Meaning | Recommended call |
|---|---|---|
connect_account | The adapter has no usable session credential for this platform. | POST /accounts/connect |
fetch_artifact | The artifact may have changed state. | GET /artifacts/{id} |
fetch_pipeline | The pipeline may have changed state. | GET /pipelines/{id} |
diagnose_pipeline | The pipeline is unhealthy. | GET /pipelines/{id}/diagnose |
If you see a suggested_action not in this list, it's a forward-compatible value — log it and surface to the operator.
Rate limits
The Agent API rate-limits per token. Defaults:
- Soft limit: 600 requests / minute per token.
- Burst window: rolling 1 minute.
Headers emitted on every authenticated response (not just 429):
| Header | Value |
|---|---|
RateLimit-Limit | 600 |
RateLimit-Remaining | integer |
RateLimit-Reset | seconds until reset |
On 429:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
RateLimit-Limit: 600
RateLimit-Remaining: 0
RateLimit-Reset: 60
Recommended handling pattern
async function call(method: string, path: string, body?: object) {
const res = await fetch(`${WHET_BASE_URL}${path}`, {
method,
headers: {
"Authorization": `Bearer ${WHET_TOKEN}`,
"Content-Type": "application/json",
},
body: body ? JSON.stringify(body) : undefined,
});
if (res.ok) return res.json();
const { error } = await res.json();
const requestId = res.headers.get("X-Request-Id");
switch (error.code) {
case "rate_limited": {
const retryAfter = Number(res.headers.get("Retry-After") ?? "5");
await sleep(retryAfter * 1000);
return call(method, path, body);
}
case "credential_dead":
case "credential_missing":
throw new CredentialError(error, requestId);
case "validation_failed":
throw new ValidationError(error, requestId);
case "unauthorized":
throw new AuthError(error, requestId);
default:
throw new ApiError(error, requestId);
}
}
Log correlation
Every response includes X-Request-Id. Copy that header when reporting an incident. The local Whet Desktop log file is indexed by the same id (default: ~/.whet/logs/whet.log on macOS/Linux, %LOCALAPPDATA%\Whet\logs\whet.log on Windows).
See also: Authentication, Idempotency, Webhooks.