Error Handling
AgentsForms surfaces errors in a structured format designed for both humans and AI agents. Every error response includes a machine-readable code and a human-readable message.
Error response shape
Section titled “Error response shape”{ "error": { "code": "validation_failed", "message": "Invalid form definition", "details": [ { "path": "fields.0.id", "code": "invalid_string", "message": "Field id must start with a letter and contain only [a-zA-Z0-9_.-]" } ] }}| Field | Description |
|---|---|
error.code | Stable error code. Use for programmatic branching. |
error.message | Human-readable summary. Show to developers. |
error.details | Array of per-field or per-constraint issues. Each has a path, code, and message. |
Error codes
Section titled “Error codes”| Code | HTTP | Meaning |
|---|---|---|
validation_failed | 422 | The form definition or request body is invalid. Check details. |
not_found | 404 | The requested form, session, or submission does not exist. |
unauthorized | 401 | Missing or invalid API key. |
internal_error | 500 | Something went wrong on the server. Retry with backoff. |
duplicate_field_id | 422 | Two fields share the same id. |
select_options_required | 422 | A select / multi_select / radio field has no options. |
too_big | 422 | The form has more than 100 fields. |
Handling validation in agents
Section titled “Handling validation in agents”When your agent receives a validation_failed error while creating a form:
async function createForm(definition: unknown) { const resp = await agentsForms.forms.create(definition);
if (resp.error?.code === 'validation_failed') { // Feed the errors back to your LLM for self-correction const errorSummary = resp.error.details .map((d) => `${d.path}: ${d.message}`) .join('\n'); return { needsRetry: true, errors: errorSummary }; }
return resp.form;}The agent can use the structured error to fix the form definition and retry.
Retry strategy
Section titled “Retry strategy”For transient errors (internal_error, network timeouts):
async function withRetry<T>(fn: () => Promise<T>, maxAttempts = 3): Promise<T> { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (err) { if (attempt === maxAttempts) throw err; const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s await new Promise((r) => setTimeout(r, delay)); } } throw new Error('unreachable');}Do not retry validation_failed or unauthorized — these will not succeed on retry without changes.