Error Handling

Understanding how the Udacity Public API communicates errors will help you build robust integrations.

Response Structure

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.

Successful Response
{
  "data": {
    "programProgress": {
      "totalCount": 42,
      "edges": [ ... ]
    }
  }
}
Error Response
{
  "data": null,
  "errors": [
    {
      "message": "not authorized",
      "path": ["programProgress"],
      "extensions": {
        "code": "UNAUTHORIZED"
      }
    }
  ]
}
Partial Error
{
  "data": {
    "programProgress": {
      "totalCount": 42,
      "edges": [ ... ],
      "pageInfo": null
    }
  },
  "errors": [
    {
      "message": "internal error fetching pageInfo",
      "path": ["programProgress", "pageInfo"]
    }
  ]
}
HTTP Status

HTTP status codes

GraphQL APIs typically return 200 OK even when there are query-level errors. Always check the errors array.

200 OK

Request processed — check errors array for GraphQL-level errors.

401 Unauthorized

Missing or invalid authentication token.

403 Forbidden

Token is valid but lacks the required scope.

429 Too Many Requests

Rate limit exceeded — see Rate Limits.

500 Internal Server Error

Unexpected server error.

Common Errors

Authentication & validation errors

Missing required scope means your token doesn’t have the required scope. Check Authentication for the required scopes per API domain.

Auth Errors
// Missing token:
{ "errors": [{ "message": "no Authorization header" }] }

// Invalid token:
{ "errors": [{ "message": "token not found" }] }

// Expired or revoked:
{ "errors": [{ "message": "token is no longer valid" }] }
Validation Errors
// Invalid query syntax:
{ "errors": [{ "message": "Expected Name, found }" }] }

// Unknown field:
{ "errors": [{ "message": "Cannot query field \"unknownField\" on type \"ProgramProgressRecord\"" }] }
Implementation

Handling errors in code

A robust error-handling wrapper that covers HTTP-level and GraphQL-level errors.

Error Handler
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;
}
Best Practices

Recommendations

  • Always check the errors array in GraphQL responses, even on 200 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