mastra-ai/mastra · error · Error

Course state update failed with status ${response.status}: $

Error message

Course state update failed with status ${response.status}: ${response.statusText}

What it means

The POST to https://mastra.ai/api/course/update returned a non-OK HTTP status. The server rejected the state sync (auth failure, validation error, server error), and the library surfaces the status code and status text.

Source

Thrown at packages/mcp-docs-server/src/tools/course.ts:283

  const creds = await getDeviceCredentials();
  if (!creds) {
    throw new Error('Device credentials not found.');
  }

  const response = await fetch('https://mastra.ai/api/course/update', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-mastra-course-key': creds.key,
    },
    body: JSON.stringify({
      id: creds.deviceId,
      state: state,
    }),
  });

  if (!response.ok) {
    throw new Error(`Course state update failed with status ${response.status}: ${response.statusText}`);
  }
}

async function saveCourseState(state: CourseState, deviceId: string | null): Promise<void> {
  // If no device ID, the user isn't registered - this is an error condition
  if (!deviceId) {
    throw new Error('Cannot save course state: User is not registered');
  }
  const statePath = await getCourseStatePath();
  try {
    // Save to local filesystem
    await fs.writeFile(statePath, JSON.stringify(state, null, 2), 'utf-8');
    // Sync with server
    try {
      // Use getDeviceCredentials to ensure we have the key
      const creds = await getDeviceCredentials();
      if (!creds) throw new Error('Device credentials not found');
      await updateCourseStateOnServer(creds.deviceId, state);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check the HTTP status: 401/403 → re-register the device to get fresh credentials; 5xx → retry later.
  2. Verify network/proxy access to mastra.ai from the machine.
  3. Note that the local save may still have succeeded — check local state before assuming data loss, then retry the sync.
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch('https://mastra.ai/api/course/update', { method: 'HEAD' }).catch(() => null);
if (!res || !res.ok) {
  // mastra.ai unreachable or degraded — defer sync instead of calling saveCourseState
}

Try / catch

try {
  await saveCourseState(state, deviceId);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Course state update failed with status')) {
    const status = Number(e.message.match(/status (\d+)/)?.[1]);
    if (status >= 500 || status === 429) { /* retry with backoff */ }
    else if (status === 401 || status === 403) { /* re-register device */ }
  } else throw e;
}

Prevention

When it happens

Trigger: fetch('https://mastra.ai/api/course/update') responds with 4xx/5xx: invalid or expired device credentials, malformed state payload, network-level proxy interception, or mastra.ai API outage.

Common situations: Expired/revoked device ID; corporate proxy returning 403/502; mastra.ai API downtime; course state schema changed server-side after a client update.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/5094579d3f0e095a. Report an issue: GitHub.