mastra-ai/mastra · error · Error
Failed to save course state: ${error}
Error message
Failed to save course state: ${error} What it means
The outer try/catch in saveCourseState wraps the local filesystem write of the course state file; if fs.writeFile (or getCourseStatePath) fails, the error is rethrown as 'Failed to save course state: <underlying error>'. This means the user's course progress could not be persisted locally.
Source
Thrown at packages/mcp-docs-server/src/tools/course.ts:307
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}`);
}
}
// Get the path to the course state file
async function getCourseStatePath(): Promise<string> {
const stateDirPath = path.join(os.homedir(), '.cache', 'mastra', 'course');
// Ensure the directory exists
if (!existsSync(stateDirPath)) {
mkdirSync(stateDirPath, { recursive: true });
}
return path.join(stateDirPath, 'state.json');
}
async function loadCourseState(): Promise<CourseState | null> {
const statePath = await getCourseStatePath();
View on GitHub (pinned to 75dd419e61)
Solutions
- Ensure ~/.cache/mastra/course exists and is writable (mkdir -p, fix permissions).
- Check disk space and that HOME points to a writable directory.
- Inspect the wrapped underlying error in the message for the exact fs failure code (EACCES, ENOSPC, ENOENT).
Example fix
// before
// assuming the cache dir exists
await fs.writeFile(statePath, data, 'utf-8');
// after
await fs.mkdir(path.dirname(statePath), { recursive: true });
await fs.writeFile(statePath, data, 'utf-8'); Defensive patterns
Strategy: try-catch
Validate before calling
import { accessSync, constants, mkdirSync } from 'node:fs';
import path from 'node:path';
import os from 'node:os';
const stateDir = path.join(os.homedir(), '.cache', 'mastra', 'course');
mkdirSync(stateDir, { recursive: true });
accessSync(stateDir, constants.W_OK); // throws early if not writable Try / catch
try {
await saveCourseState(state, deviceId);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Failed to save course state:')) {
// inspect wrapped fs error (EACCES/ENOSPC/ENOENT) and fix dir perms/disk/HOME
} else throw e;
} Prevention
- Ensure ~/.cache/mastra/course exists and is writable before running course tools.
- Verify HOME points to a writable directory in containers and CI.
- Watch disk space; ENOSPC produces this wrapped error.
When it happens
Trigger: fs.writeFile to ~/.cache/mastra/course/<state file> rejects: the cache directory does not exist and was not created, disk full, permission denied on ~/.cache, or a read-only filesystem.
Common situations: Home directory not writable in containers/CI (HOME set to a read-only path); deleted ~/.cache/mastra mid-session; ENOSPC on full disks; sandboxed environments blocking writes to $HOME.
Related errors
- readFile ${path} failed (exit ${result.exitCode}): ${result.
- One or more process memory diagnostic artifact writes failed
- Failed to create directory: ${errorMessage}
- Failed to write scorer: ${errorMessage}
- EACCES
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/2d6bc6842274b088.
Report an issue: GitHub.