Documentation Index
Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
Use this file to discover all available pages before exploring further.
GraphQL errors follow the standard GraphQL error format with additional extensions for error codes.
{
"errors": [
{
"message": "Human-readable error message",
"extensions": {
"code": "ERROR_CODE",
"additionalInfo": "..."
},
"path": ["queryName", "fieldName"]
}
],
"data": {
"queryName": null
}
}
Common Error Codes
| Code | HTTP Status | Description |
|---|
NOT_FOUND | 404 | Resource not found |
UNAUTHORIZED | 401 | Invalid or missing API key |
FORBIDDEN | 403 | Insufficient permissions |
BAD_REQUEST | 400 | Invalid query or variables |
INTERNAL_ERROR | 500 | Server error |
Preview-Specific Error Codes
| Code | Description |
|---|
INVALID_PREVIEW_TOKEN | Invalid or expired preview token |
PREVIEW_NOT_FOUND | Preview resource not found or deleted |
VERSION_NOT_FOUND | Component version not found |
MISSING_PREVIEW_TOKEN | Preview token required but not provided |
Error Examples
Resource Not Found
{
"errors": [
{
"message": "Content not found",
"extensions": {
"code": "NOT_FOUND",
"id": "cont999"
},
"path": ["content"]
}
],
"data": {
"content": null
}
}
Unauthorized
{
"errors": [
{
"message": "Invalid or missing API key",
"extensions": {
"code": "UNAUTHORIZED"
}
}
]
}
Invalid Preview Token
{
"errors": [
{
"message": "Invalid or expired preview token",
"extensions": {
"code": "INVALID_PREVIEW_TOKEN"
},
"path": ["preview"]
}
],
"data": { "preview": null }
}
Version Not Found
{
"errors": [
{
"message": "Component version not found",
"extensions": {
"code": "VERSION_NOT_FOUND",
"version": 5
},
"path": ["preview"]
}
],
"data": { "preview": null }
}
Validation Error
{
"errors": [
{
"message": "Variable \"$id\" of required type \"ID!\" was not provided.",
"extensions": {
"code": "BAD_REQUEST"
},
"locations": [{ "line": 1, "column": 7 }]
}
]
}
Client-Side Error Handling
JavaScript
async function fetchContent(id) {
const response = await fetch('https://api.metabind.ai/graphql', {
method: 'POST',
headers: {
'x-api-key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: GET_CONTENT_QUERY,
variables: { id }
})
});
const { data, errors } = await response.json();
if (errors) {
for (const error of errors) {
switch (error.extensions?.code) {
case 'NOT_FOUND':
console.warn(`Content ${id} not found`);
return null;
case 'UNAUTHORIZED':
throw new Error('Invalid API key');
default:
console.error('GraphQL error:', error.message);
}
}
}
return data?.content;
}
Apollo Client
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { onError } from '@apollo/client/link/error';
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
for (const { message, extensions, path } of graphQLErrors) {
switch (extensions?.code) {
case 'UNAUTHORIZED':
// Redirect to login or refresh API key
handleUnauthorized();
break;
case 'NOT_FOUND':
console.warn(`Resource not found at ${path?.join('.')}`);
break;
case 'INVALID_PREVIEW_TOKEN':
// Preview token expired
handleExpiredPreview();
break;
default:
console.error(`GraphQL error: ${message}`);
}
}
}
if (networkError) {
console.error(`Network error: ${networkError}`);
}
});
const client = new ApolloClient({
link: errorLink.concat(httpLink),
cache: new InMemoryCache()
});
React Hook
function useContent(id) {
const { data, loading, error } = useQuery(GET_CONTENT, {
variables: { id },
errorPolicy: 'all' // Return partial data with errors
});
if (error) {
const graphQLError = error.graphQLErrors?.[0];
if (graphQLError?.extensions?.code === 'NOT_FOUND') {
return { content: null, loading: false, notFound: true };
}
throw error; // Re-throw unexpected errors
}
return { content: data?.content, loading, notFound: false };
}
Subscription Error Handling
import { createClient } from 'graphql-ws';
const client = createClient({
url: 'wss://api.metabind.ai/graphql',
connectionParams: {
headers: { 'x-api-key': API_KEY }
},
on: {
error: (error) => {
console.error('WebSocket error:', error);
},
closed: () => {
console.log('WebSocket closed');
}
},
retryAttempts: 5,
shouldRetry: () => true
});
client.subscribe({
query: CONTENT_UPDATED,
variables: { id: 'cont123' }
}, {
next: (data) => {
if (data.errors) {
for (const error of data.errors) {
console.error('Subscription error:', error.message);
}
return;
}
handleUpdate(data.data.contentUpdated);
},
error: (err) => {
console.error('Subscription error:', err);
},
complete: () => {
console.log('Subscription complete');
}
});
Best Practices
- Always check for errors: GraphQL can return partial data with errors
- Use error codes: Check
extensions.code for programmatic error handling
- Handle NOT_FOUND gracefully: Resources may be deleted or unpublished
- Implement retry logic: Network errors may be transient
- Log errors: Include path and extensions for debugging
- Differentiate preview errors: Preview tokens can expire independently of API keys