Skip to content

Errors Reference

SDK methods reject with ConfigureError for API, validation, permission, tool, timeout, and network failures.

ts
import { ConfigureError, ErrorCode } from "configure";

try {
  await profile.executeTool(toolCall);
} catch (error) {
  if (error instanceof ConfigureError) {
    console.error(error.code, error.statusCode, error.type, error.requestId);
  }
}

Error Codes

ErrorCode exports these values:

CodeTypical meaning
API_KEY_MISSINGNo API key was provided and CONFIGURE_API_KEY was not set.
AUTH_REQUIREDToken is missing, invalid, expired, or rejected by the API.
INVALID_INPUTSDK-side or API-side input validation failed.
TOOL_NOT_CONNECTEDA connector-backed tool requires a user connection that is not available.
NETWORK_ERRORFetch failed before an API response was received.
RATE_LIMITEDThe API returned a rate limit response.
NOT_FOUNDThe requested resource was not found. Reachable only from legacy unstructured responses; structured backend 404s arrive as INVALID_INPUT.
SERVER_ERRORThe backend returned a 5xx or structured API error.
TIMEOUTThe request timed out.
ACCESS_DENIEDThe current profile object is not allowed to access the requested resource or tool.
TOOL_ERRORA connector or provider operation failed.
PAYMENT_REQUIREDBilling or quota limits blocked the request.
COMMIT_REQUIREDA profile read created a write-back obligation; call profile.commit() (server-side write-back), then retry the read. The model-facing commit tool is not in the default tool set; it exists only for MCP/adapter runtimes via tools({ advanced: { commit: true } }).

Common cases map to those codes:

  • Missing linked token or app-local externalId: INVALID_INPUT.
  • Invalid or reserved agent handle: INVALID_INPUT.
  • Any tool name not in the enabled set, unknown or not: ACCESS_DENIED. executeTool() checks the enabled set first, so the INVALID_INPUT unknown-tool branch at dispatch is practically unreachable.
  • Malformed forget id (anything other than mem_ plus 32 hex characters): INVALID_INPUT. An unknown id or another agent's memory does not throw at all; forget() resolves with { deleted: false, message } because deletion is own-namespace only. Check response.deleted, not just the catch block.
  • Missing connector connection: TOOL_NOT_CONNECTED.
  • Backend API error: SERVER_ERROR.
  • Structured backend 404s (resource_missing, agent_not_found): INVALID_INPUT with statusCode 404, not NOT_FOUND. NOT_FOUND appears only for legacy unstructured responses. Branch on statusCode === 404 to catch both.

Recover from AUTH_REQUIRED and TOOL_NOT_CONNECTED through the hosted flows: send the user through sign-in or reconnect with reason: "signin" | "reconnect" | "permissions". See Auth Flows.

Structured Fields

ConfigureError exposes fields directly:

  • code
  • statusCode
  • type
  • param
  • retryable
  • suggestedAction
  • docUrl
  • retryAfter
  • requestId

There is no status or details property on ConfigureError.

retryable is set only from structured backend responses. The backend marks the plain rate-limit code, transient tool failures, and 5xx-class errors as retryable: true. OTP throttling (otp_blocked) also surfaces as RATE_LIMITED, but with retryable: false. Errors the SDK creates locally (TIMEOUT and NETWORK_ERROR) leave retryable undefined, not false. A retry loop that checks error.retryable === true therefore never retries local timeouts or network failures; branch on those codes explicitly if you want to retry them.

retryAfter is a number of seconds to wait before retrying. The backend sets it on rate limits; otherwise it is undefined.

suggestedAction is a closed machine-actionable enum, not free text: reauthenticate, fix_request, connect_tool, retry, upgrade_plan, specify_agent, use_secret_key, check_permissions, use_hosted_auth, complete_approval, or commit_profile. Use it as the programmatic hook for recovery branches.

Tool Rejection Behavior

Call profile.tools() with the same connector and action options you intend to execute. tools() is synchronous and returns ConfigureToolDefinition[]; do not await it. tools() records the enabled names; profile.executeTool(toolCall: ConfigureToolCall): Promise<unknown> rejects any name outside that recorded set with ACCESS_DENIED. Before any tools() call the set holds the four default profile tools. toolCall accepts { name, arguments }, { name, input }, or { function: { name, arguments } }; arguments can be a JSON string.

ts
profile.tools({ connectors: ["gmail"] });

await profile.executeTool({
  name: "configure_email_send",
  arguments: {},
}); // throws ConfigureError with code ACCESS_DENIED

Personalization infrastructure for agents