mastra-ai/mastra · error · Error
Failed to load course state: ${error}
Error message
Failed to load course state: ${error} What it means
loadCourseState reads and JSON.parses the locally stored course state file. If reading or parsing fails (corrupt JSON, unreadable file), it throws 'Failed to load course state: <error>'. A missing file is NOT an error — it returns null.
Source
Thrown at packages/mcp-docs-server/src/tools/course.ts:332
// 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();
try {
if (existsSync(statePath)) {
const stateData = await fs.readFile(statePath, 'utf-8');
return JSON.parse(stateData) as CourseState;
}
} catch (error) {
throw new Error(`Failed to load course state: ${error}`);
}
return null;
}
async function scanCourseContent(): Promise<CourseState> {
// Scan the course directory to build a fresh state
const lessonDirs = await fs.readdir(courseDir);
const lessons = await Promise.all(
lessonDirs
.filter(dir => !dir.startsWith('.')) // Skip hidden directories
.sort((a, b) => a.localeCompare(b))
.map(async lessonDir => {
const lessonPath = path.join(courseDir, lessonDir);
const lessonStats = await fs.stat(lessonPath);
if (!lessonStats.isDirectory()) return null;View on GitHub (pinned to 75dd419e61)
Solutions
- Delete or fix the corrupted state file at ~/.cache/mastra/course so it contains valid JSON (or let it be recreated).
- Validate the JSON with a parser and repair the fields you need.
- Check file permissions if the message wraps an EACCES read error.
Example fix
// before
// corrupted state file read directly
const state = await loadCourseState();
// after
// reset corrupt local state
await fs.rm(statePath, { force: true });
const state = await loadCourseState(); // returns null, then re-initialized Defensive patterns
Strategy: try-catch
Validate before calling
import { existsSync } from 'node:fs';
import { readFileSync } from 'node:fs';
if (existsSync(statePath)) {
try { JSON.parse(readFileSync(statePath, 'utf-8')); } catch {
// corrupt state file — delete or repair before calling loadCourseState
}
} Type guard
function isValidCourseState(v: unknown): v is CourseState {
return typeof v === 'object' && v !== null;
} Try / catch
let state: CourseState | null = null;
try {
state = await loadCourseState();
} catch (e) {
if (e instanceof Error && e.message.startsWith('Failed to load course state:')) {
state = null; // reset to fresh state; optionally delete the corrupt file
} else throw e;
} Prevention
- Treat null (missing file) as 'fresh state' — only catch-and-reset on parse errors.
- Never hand-edit the course state JSON; if you do, validate it afterwards.
- Write state atomically (tmp file + rename) to avoid truncated files on crash.
When it happens
Trigger: fs.readFile succeeds but the file contains invalid JSON (manual edits, truncated write from a previous crash), or readFile itself fails on an existing but unreadable statePath.
Common situations: State file corrupted by a prior ENOSPC-interrupted write; user hand-edited ~/.cache/mastra/course state and broke JSON; permissions changed on the cache file.
Related errors
- Failed to parse existing package.json at ${targetPkgPath}: $
- Failed to parse A2A stream event: ${error instanceof Error ?
- MASTRA_ENTRY_FILE_NOT_FOUND
- Failed to copy studio assets from "${studioSource}" to "${st
- Failed to copy studio assets from "${studioSource}" to "${st
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/7d75841cc69796d1.
Report an issue: GitHub.