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

  1. Fix the offending entry to true or {solved: true, best: true}
  2. Booleans only: 1/"true" are not accepted — coerce before importing
  3. 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

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.