affaan-m/ECC · warning

! ${contextDir}: invalid meta.json, continuing with defaul

Error message

  ! ${contextDir}: invalid meta.json, continuing with defaults (${e.message})

What it means

During the ck context-dir v1->v2 migration (skills/ck/commands/migrate.mjs), each directory may carry a v1 meta.json sidecar. If readFileSync succeeds but JSON.parse throws (syntax error, empty file, BOM, merge-conflict markers), the migrator prints this warning and continues with `meta = {}` defaults, deriving everything else from CONTEXT.md sections instead. It is non-fatal by design, but metadata that lived only in meta.json is silently lost.

Source

Thrown at skills/ck/commands/migrate.mjs:118

      if (existing.version === 2) {
        console.log(`  ✓ ${contextDir} — already v2, skipping`);
        skipped++;
        continue;
      }
    } catch { /* fall through to migrate */ }
  }

  console.log(`\n  → Migrating: ${contextDir}`);

  try {
    // Read v1 files
    const contextMd = existsSync(contextMdPath) ? readFileSync(contextMdPath, 'utf8') : '';
    let meta = {};
    if (existsSync(metaPath)) {
      try {
        meta = JSON.parse(readFileSync(metaPath, 'utf8'));
      } catch (e) {
        console.warn(`  ! ${contextDir}: invalid meta.json, continuing with defaults (${e.message})`);
      }
    }

    // Extract fields from CONTEXT.md
    const description   = extractSection(contextMd, 'What This Is') || extractSection(contextMd, 'About') || null;
    const stackRaw      = extractSection(contextMd, 'Tech Stack') || '';
    const stack         = stackRaw.split(/[,\n]/).map(s => s.replace(/^[-*]\s+/, '').trim()).filter(Boolean);
    const goal          = (extractSection(contextMd, 'Current Goal') || '').split('\n')[0].trim() || null;
    const constraintRaw = extractSection(contextMd, 'Do Not Do') || '';
    const constraints   = parseBullets(constraintRaw);
    const decisionsRaw  = extractSection(contextMd, 'Decisions Made') || '';
    const decisions     = parseDecisionsTable(decisionsRaw);
    const nextStepsRaw  = extractSection(contextMd, 'Next Steps') || '';
    const nextSteps     = parseBullets(nextStepsRaw);
    const blockersRaw   = extractSection(contextMd, 'Blockers') || '';
    const blockers      = parseBullets(blockersRaw).filter(b => b.toLowerCase() !== 'none');
    const leftOffRaw    = extractSection(contextMd, 'Where I Left Off') || '';
    const leftOffParsed = parseLeftOff(leftOffRaw);

View on GitHub (pinned to d8409a4b08)

Solutions

  1. Locate the parse error precisely: node -e "JSON.parse(require('fs').readFileSync('meta.json','utf8'))" from the context dir.
  2. Fix the JSON (remove comments/trailing commas, resolve conflict markers, re-save without BOM) and re-run the migration for that directory.
  3. If the file is intentionally empty or meaningless, delete it — absence is handled without a warning.
  4. After a defaulted migration, re-add any metadata that mattered; it was not carried over.

Example fix

before (meta.json):
{ "tags": ["a", "b",], }   // trailing comma + comment -> warning, defaults used

after:
{ "tags": ["a", "b"] }
Defensive patterns

Strategy: fallback

Validate before calling

import { readFileSync } from 'node:fs';
function parseMeta(p) {
  try {
    return { ok: true, meta: JSON.parse(readFileSync(p, 'utf8')) };
  } catch (e) {
    return { ok: false, error: e.message };
  }
}
// before migrating a context dir, surface bad files instead of silently defaulting:
const r = parseMeta(metaPath);
if (!r.ok) console.error(`${contextDir}: fix meta.json first (${r.error})`);

Type guard

function isPlainObject(v) {
  return typeof v === 'object' && v !== null && !Array.isArray(v);
}

Try / catch

let meta = {};
try {
  meta = JSON.parse(readFileSync(metaPath, 'utf8'));
} catch (e) {
  console.warn(`  ! ${contextDir}: invalid meta.json, continuing with defaults (${e.message})`);
  // optionally: record contextDir in a repair list to fix after the batch run
}

Prevention

When it happens

Trigger: Hand-edited meta.json containing comments, single quotes, or trailing commas; empty or truncated files; git merge conflicts leaving <<<<<<< / >>>>>>> markers; files saved as UTF-8 with BOM which JSON.parse rejects.

Common situations: Legacy contexts edited in editors without JSON validation; migration runs over many dirs where one bad file warns and proceeds; users surprised that migrated contexts lack original metadata because defaults were used.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@d8409a4b08 (2026-08-26). Data as JSON: /api/errors/ab744776b631fe41. Report an issue: GitHub.