{"record":{"id":"ab744776b631fe41","repo":"affaan-m/ECC","slug":"contextdir-invalid-meta-json-continuing-w","errorCode":null,"errorMessage":"  ! ${contextDir}: invalid meta.json, continuing with defaults (${e.message})","messagePattern":"  ! (.+?): invalid meta\\.json, continuing with defaults \\((.+?)\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"skills/ck/commands/migrate.mjs","lineNumber":118,"sourceCode":"      if (existing.version === 2) {\n        console.log(`  ✓ ${contextDir} — already v2, skipping`);\n        skipped++;\n        continue;\n      }\n    } catch { /* fall through to migrate */ }\n  }\n\n  console.log(`\\n  → Migrating: ${contextDir}`);\n\n  try {\n    // Read v1 files\n    const contextMd = existsSync(contextMdPath) ? readFileSync(contextMdPath, 'utf8') : '';\n    let meta = {};\n    if (existsSync(metaPath)) {\n      try {\n        meta = JSON.parse(readFileSync(metaPath, 'utf8'));\n      } catch (e) {\n        console.warn(`  ! ${contextDir}: invalid meta.json, continuing with defaults (${e.message})`);\n      }\n    }\n\n    // Extract fields from CONTEXT.md\n    const description   = extractSection(contextMd, 'What This Is') || extractSection(contextMd, 'About') || null;\n    const stackRaw      = extractSection(contextMd, 'Tech Stack') || '';\n    const stack         = stackRaw.split(/[,\\n]/).map(s => s.replace(/^[-*]\\s+/, '').trim()).filter(Boolean);\n    const goal          = (extractSection(contextMd, 'Current Goal') || '').split('\\n')[0].trim() || null;\n    const constraintRaw = extractSection(contextMd, 'Do Not Do') || '';\n    const constraints   = parseBullets(constraintRaw);\n    const decisionsRaw  = extractSection(contextMd, 'Decisions Made') || '';\n    const decisions     = parseDecisionsTable(decisionsRaw);\n    const nextStepsRaw  = extractSection(contextMd, 'Next Steps') || '';\n    const nextSteps     = parseBullets(nextStepsRaw);\n    const blockersRaw   = extractSection(contextMd, 'Blockers') || '';\n    const blockers      = parseBullets(blockersRaw).filter(b => b.toLowerCase() !== 'none');\n    const leftOffRaw    = extractSection(contextMd, 'Where I Left Off') || '';\n    const leftOffParsed = parseLeftOff(leftOffRaw);","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/affaan-m/ECC/blob/d8409a4b0813771235555e32e3d8046a73988bfa/skills/ck/commands/migrate.mjs#L100-L136","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Locate the parse error precisely: node -e \"JSON.parse(require('fs').readFileSync('meta.json','utf8'))\" from the context dir.","Fix the JSON (remove comments/trailing commas, resolve conflict markers, re-save without BOM) and re-run the migration for that directory.","If the file is intentionally empty or meaningless, delete it — absence is handled without a warning.","After a defaulted migration, re-add any metadata that mattered; it was not carried over."],"exampleFix":"before (meta.json):\n{ \"tags\": [\"a\", \"b\",], }   // trailing comma + comment -> warning, defaults used\n\nafter:\n{ \"tags\": [\"a\", \"b\"] }","handlingStrategy":"fallback","validationCode":"import { readFileSync } from 'node:fs';\nfunction parseMeta(p) {\n  try {\n    return { ok: true, meta: JSON.parse(readFileSync(p, 'utf8')) };\n  } catch (e) {\n    return { ok: false, error: e.message };\n  }\n}\n// before migrating a context dir, surface bad files instead of silently defaulting:\nconst r = parseMeta(metaPath);\nif (!r.ok) console.error(`${contextDir}: fix meta.json first (${r.error})`);","typeGuard":"function isPlainObject(v) {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"let meta = {};\ntry {\n  meta = JSON.parse(readFileSync(metaPath, 'utf8'));\n} catch (e) {\n  console.warn(`  ! ${contextDir}: invalid meta.json, continuing with defaults (${e.message})`);\n  // optionally: record contextDir in a repair list to fix after the batch run\n}","preventionTips":["Run `npx jsonlint` (or `node -e \"JSON.parse(...)\"`) over meta.json files before migrations.","Use a JSON-aware editor/prettier so comments, trailing commas, and BOM never creep in.","Resolve git merge conflicts in JSON files instead of committing markers.","After any migration that printed this warning, diff the migrated output against the original meta.json to recover dropped metadata."],"tags":["json","node","migration","cli","javascript"],"backgroundTag":"json-parse-error","analyzedSha":"d8409a4b0813771235555e32e3d8046a73988bfa","analyzedAt":"2026-08-26T12:15:34.022Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}