Error Handling
GraphQL errors are returned in the errors array of the response. The HTTP status code is always 200 — check the response body for errors.
Error Response Format
{
"errors": [
{
"message": "Unauthenticated.",
"extensions": {
"category": "authentication"
},
"locations": [{ "line": 2, "column": 3 }],
"path": ["me"]
}
],
"data": null
}Error Categories
| Field | Type | Description |
|---|---|---|
| authentication | 401 | Invalid or missing API key / token — check credentials |
| authorization | 403 | Insufficient permissions — check user role and abilities |
| validation | 422 | Invalid input — check extensions.validation for field details |
| internal | 500 | Server error — retry with exponential backoff |
Validation Errors
Validation errors include field-level details:
{
"errors": [{
"message": "Validation failed for the field [createPeople].",
"extensions": {
"category": "validation",
"validation": {
"input.email": ["The email field is required."],
"input.firstname": ["The firstname field is required."]
}
}
}]
}Best Practices
- Always check for the
errorsarray in the response body - For
authenticationerrors, refresh your token withrefreshToken - For
validationerrors, checkextensions.validationfor field-level details - Implement exponential backoff for
internalerrors (start at 1s, max 30s) - Log the full error object including
pathfor debugging
Handling in Code
// With @kanvas/core SDK
try {
const lead = await kanvas.leads.createLead(input);
} catch (err) {
if (err.graphQLErrors) {
for (const error of err.graphQLErrors) {
console.error(error.message);
console.error(error.extensions?.category);
console.error(error.extensions?.validation);
}
}
if (err.networkError) {
console.error("Network error:", err.networkError.message);
}
}
// With raw fetch
const json = await res.json();
if (json.errors) {
json.errors.forEach(e => console.error(e.message));
} else {
// Use json.data
}