pcottle/learnGitBranching · error · Error
invalid progress data for level: {}
Error message
invalid progress data for level: {} What it means
The per-level check inside _normalizeImportedSolvedMap(): each value in the progress object must be the boolean true (legacy shorthand for 'solved') or an object with solved/best booleans. Anything else — null, arrays, strings, numbers — throws Error('invalid progress data for level: ' + levelID) identifying the offending key.
Source
Thrown at src/js/stores/LevelStore.js:79
}
function _normalizeImportedSolvedMap(progress) {
if (!progress || typeof progress !== 'object' || Array.isArray(progress)) {
throw new Error('level progress must be a JSON object');
}
var normalized = {};
Object.keys(progress).forEach(function(levelID) {
var levelData = progress[levelID];
// Backwards compatibility with the old storage format.
if (levelData === true) {
normalized[levelID] = true;
return;
}
if (!levelData || typeof levelData !== 'object' || Array.isArray(levelData)) {
throw new Error('invalid progress data for level: ' + levelID);
}
normalized[levelID] = {
solved: levelData.solved === true,
best: levelData.best === true
};
});
return normalized;
}
function exportLevelProgress() {
return JSON.stringify(_cloneSolvedMap());
}
function importLevelProgress(progress) {
if (typeof progress === 'string') {
progress = JSON.parse(progress);View on GitHub (pinned to 5b09d0ff96)
Solutions
- Fix the offending entry to true or {solved: true, best: true}
- Booleans only: 1/"true" are not accepted — coerce before importing
- Use the error's levelID to locate the bad key quickly in the JSON
Example fix
// before
{"intro-1": "true"}
// after
{"intro-1": true} Defensive patterns
Strategy: validation
Validate before calling
function isValidLevelEntry(v) {
return v === true ||
(Boolean(v) && typeof v === 'object' && !Array.isArray(v) &&
typeof v.solved === 'boolean' && typeof v.best === 'boolean');
}
Object.keys(data).forEach(k => { if (!isValidLevelEntry(data[k])) throw new Error('bad level: ' + k); }); Type guard
function isLevelEntry(v) {
if (v === true) return true;
return v !== null && typeof v === 'object' && !Array.isArray(v) &&
typeof v.solved === 'boolean' && typeof v.best === 'boolean';
} Try / catch
try { importLevelProgress(data); } catch (e) { if (/invalid progress data/.test(e.message)) { highlightBadLevel(e.message.split(': ')[1]); } else throw e; } Prevention
- Store solved/best strictly as booleans, never 1/"true"
- Sanitize legacy saves before import, coercing truthy values to true
When it happens
Trigger: Calling importLevelProgress() with a progress map containing an invalid entry, e.g. {"intro-1": "yes"}, {"intro-1": null}, or {"intro-1": ["solved"]}.
Common situations: Legacy saves where solved was stored as 1 or "true"; partially migrated export formats; typos when hand-editing save JSON.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
AI-assisted analysis of pcottle/learnGitBranching@5b09d0ff96 (2026-08-27).
Data as JSON: /api/errors/c8a84a2f4fb42f14.
Report an issue: GitHub.