{"record":{"id":"ccf31724cb13001c","repo":"pbakaus/impeccable","slug":"config-json-must-be-an-object","errorCode":null,"errorMessage":"config.json must be an object","messagePattern":"config\\.json must be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/skills/impeccable/scripts/live-inject.mjs","lineNumber":450,"sourceCode":"      re += '[^/]';\n      i += 1;\n    } else if (/[.+^${}()|[\\]\\\\]/.test(c)) {\n      re += '\\\\' + c;\n      i += 1;\n    } else {\n      re += c;\n      i += 1;\n    }\n  }\n  return new RegExp('^' + re + '$');\n}\n\n// ---------------------------------------------------------------------------\n// Core operations\n// ---------------------------------------------------------------------------\n\nfunction validateConfig(cfg) {\n  if (!cfg || typeof cfg !== 'object') throw new Error('config.json must be an object');\n  if (!Array.isArray(cfg.files) || cfg.files.length === 0) {\n    throw new Error('config.files (non-empty string array) required');\n  }\n  if (!cfg.files.every((f) => typeof f === 'string' && f.length > 0)) {\n    throw new Error('config.files must contain only non-empty strings');\n  }\n  if (cfg.exclude !== undefined) {\n    if (!Array.isArray(cfg.exclude)) {\n      throw new Error('config.exclude, if present, must be a string array');\n    }\n    if (!cfg.exclude.every((f) => typeof f === 'string' && f.length > 0)) {\n      throw new Error('config.exclude must contain only non-empty strings');\n    }\n  }\n  if (typeof cfg.insertBefore !== 'string' && typeof cfg.insertAfter !== 'string') {\n    throw new Error('config.insertBefore or config.insertAfter (string) required');\n  }\n  if (cfg.commentSyntax !== 'html' && cfg.commentSyntax !== 'jsx') {","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/pbakaus/impeccable/blob/d14711ae3d1a1dd62dee61a358d27f107c51ccd0/plugin/skills/impeccable/scripts/live-inject.mjs#L432-L468","documentation":"First check in validateConfig() for the live-inject config.json: cfg must be a non-null object. Fires when JSON.parse succeeded but produced a primitive (string/number/boolean/null) or an array. Arrays are objects but this check uses a plain typeof === 'object' truthy test, so an array would actually pass this line and fail later — the real trigger is null, undefined, or a non-object.","triggerScenarios":"config.json contains a bare string (e.g. '\"src/index.html\"'), a number, true/false, or the literal 'null'; JSON.parse of an empty file (throws, so different error) — but a file containing just 'null' parses to null and hits this. Called from injectCli() at line 141 (--check path) or line 156 (insert/remove path) after JSON.parse.","commonSituations":"Hand-edited config.json replaced the object with a single value; a code generator wrote a bare filename string instead of an object; merge conflict left 'null' as the resolved content; the file was overwritten by a tool that serialised a non-object. The CLI catches this and prints {ok:false, error:'config_invalid', message:...} rather than crashing.","solutions":["Make .impeccable/live/config.json a JSON object literal: { ... } with the required keys (files, commentSyntax, insertBefore/insertAfter).","If generating the file programmatically, ensure you JSON.stringify an object, not a string/number.","Run `node live-inject.mjs --check` to see the exact parse/validation error before attempting insert/remove.","Regenerate the config by re-running the live-mode setup flow rather than hand-editing."],"exampleFix":"// before — .impeccable/live/config.json\n\"src/index.html\"\n\n// after\n{\n  \"files\": [\"index.html\"],\n  \"commentSyntax\": \"html\",\n  \"insertBefore\": \"</head>\"\n}","handlingStrategy":"validation","validationCode":"function isValidInjectConfigShape(cfg) {\n  return cfg !== null && typeof cfg === 'object' && !Array.isArray(cfg);\n}\nconst cfg = JSON.parse(raw);\nif (!isValidInjectConfigShape(cfg)) {\n  throw new Error('config.json must be a JSON object literal');\n}","typeGuard":"/** True for a plain object (not null, not array). */\nfunction isPlainObject(value) {\n  return value !== null && typeof value === 'object' && !Array.isArray(value);\n}","tryCatchPattern":"try {\n  validateConfig(cfg);\n} catch (err) {\n  if (/must be an object/.test(err.message)) {\n    console.error('config.json is not an object literal. Regenerate via live setup.');\n    process.exit(1);\n  }\n  throw err;\n}","preventionTips":["Always JSON.stringify an object when generating config.json — never a primitive.","Run `node live-inject.mjs --check` after editing config; it prints config_invalid without mutating files.","Regenerate config through the setup wizard rather than hand-editing the top-level shape."],"tags":["live-inject","config","validation","json"],"backgroundTag":null,"analyzedSha":"d14711ae3d1a1dd62dee61a358d27f107c51ccd0","analyzedAt":"2026-08-13T00:52:25.771Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}