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
- Complete device registration first, then retry the course tool call.
- Use the read-only course tools (course state/content reads) if registration is not possible.
- 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
- Gate all state-mutating course tool calls behind a registered-device check.
- Register devices during onboarding/environment setup.
- Fall back to read-only course tools when registration is unavailable.
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
- State token has expired
- Clerk JWKS URI, secret key and publishable key are required,
- Cookie password must be at least 32 characters for SSO. Set
- Redirect URI is required for SSO login
- Token exchange failed: ${error}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/1dab05ac31bef4f9.
Report an issue: GitHub.