mastra-ai/mastra · error · Error

Cannot save course state: User is not registered

Error message

Cannot save course state: User is not registered

What it means

saveCourseState requires a deviceId; a null deviceId means the user is not registered. It throws this error before writing any state, treating unregistered use of state-mutating course tools as an error condition.

Source

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

    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);
    } catch {
      // Silently continue if server sync fails
      // Local save is still successful
    }
  } catch (error) {
    throw new Error(`Failed to save course state: ${error}`);
  }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Complete device registration first, then retry the course tool call.
  2. Use the read-only course tools (course state/content reads) if registration is not possible.
  3. Check getDeviceCredentials() output before calling state-mutating tools to confirm a deviceId exists.
Defensive patterns

Strategy: validation

Validate before calling

if (!deviceId) {
  // do not call state-mutating course tools; register first or use read-only tools
  throw new Error('Register the device before saving course state');
}
await saveCourseState(state, deviceId);

Type guard

function isRegistered(deviceId: string | null): deviceId is string {
  return typeof deviceId === 'string' && deviceId.length > 0;
}

Try / catch

try {
  await saveCourseState(state, deviceId);
} catch (e) {
  if (e instanceof Error && e.message.includes('User is not registered')) {
    // run device registration, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: Calling startMastraCourse, startMastraCourseLesson, or nextMastraCourseStep on an unregistered device — deviceId resolved as null because registration never happened or credentials are absent.

Common situations: First run on a new machine/container without registering; credentials wiped; tests or agents invoking state-mutating course tools without the registration prerequisite.

Related errors


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