Error Handling
Understanding how the Udacity Public API communicates errors will help you build robust integrations.
Success, errors, and partial data
GraphQL responses always include a data field. When errors occur, an errors array is also present.
GraphQL can return partial data — some fields succeed while others fail.
{
"data": {
"programProgress": {
"totalCount": 42,
"edges": [ ... ]
}
}
}{
"data": null,
"errors": [
{
"message": "not authorized",
"path": ["programProgress"],
"extensions": {
"code": "UNAUTHORIZED"
}
}
]
}{
"data": {
"programProgress": {
"totalCount": 42,
"edges": [ ... ],
"pageInfo": null
}
},
"errors": [
{
"message": "internal error fetching pageInfo",
"path": ["programProgress", "pageInfo"]
}
]
}HTTP status codes
GraphQL APIs typically return 200 OK even when there are query-level errors. Always check the errors array.
Request processed — check errors array for GraphQL-level errors.
Missing or invalid authentication token.
Token is valid but lacks the required scope.
Rate limit exceeded — see Rate Limits.
Unexpected server error.
Authentication & validation errors
Missing required scope means your token doesn’t have the required scope. Check Authentication for the required scopes per API domain.
// Missing token:
{ "errors": [{ "message": "no Authorization header" }] }
// Invalid token:
{ "errors": [{ "message": "token not found" }] }
// Expired or revoked:
{ "errors": [{ "message": "token is no longer valid" }] }// Invalid query syntax:
{ "errors": [{ "message": "Expected Name, found }" }] }
// Unknown field:
{ "errors": [{ "message": "Cannot query field \"unknownField\" on type \"ProgramProgressRecord\"" }] }Handling errors in code
A robust error-handling wrapper that covers HTTP-level and GraphQL-level errors.
async function queryAPI(query, variables) {
const response = await fetch('https://api.udacity.com/api/public/api/v1/program-progress/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${process.env.UDACITY_API_KEY}`,
},
body: JSON.stringify({ query, variables }),
});
if (response.status === 401) {
throw new Error('Authentication failed — check your API token');
}
if (response.status === 429) {
throw new Error('Rate limited — implement retry with backoff');
}
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const result = await response.json();
if (result.errors?.length > 0) {
console.error('GraphQL errors:', result.errors);
}
return result.data;
}Recommendations
- Always check the
errorsarray in GraphQL responses, even on200 OK - Log error details (message, path, extensions) for debugging
- Handle partial data gracefully — some fields may be
null - Implement retry logic for transient errors (429, 500)
- Alert on persistent auth errors (401, 403) — these usually mean a token needs rotation