{"record":{"id":"7b782715d73ba754","repo":"pbakaus/impeccable","slug":"config-insertbefore-or-config-insertafter-string-7b7827","errorCode":null,"errorMessage":"config.insertBefore or config.insertAfter (string) required","messagePattern":"config\\.insertBefore or config\\.insertAfter \\(string\\) required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skill/scripts/live-inject.mjs","lineNumber":466,"sourceCode":"\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') {\n    throw new Error(\"config.commentSyntax must be 'html' or 'jsx'\");\n  }\n  if (cfg.cspChecked !== undefined && typeof cfg.cspChecked !== 'boolean') {\n    throw new Error(\"config.cspChecked, if present, must be a boolean\");\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Auto-execute\n// ---------------------------------------------------------------------------\n\nconst _running = process.argv[1];\nif (_running?.endsWith('live-inject.mjs') || _running?.endsWith('live-inject.mjs/')) {\n  enterLiveRoot();\n  injectCli();\n}","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/pbakaus/impeccable/blob/d14711ae3d1a1dd62dee61a358d27f107c51ccd0/skill/scripts/live-inject.mjs#L448-L484","documentation":"Thrown by validateConfig() in live-inject.mjs when neither cfg.insertBefore nor cfg.insertAfter is a string. The injector needs exactly one anchor telling it where in each matched file to insert the live snippet; with no string anchor it has no safe insertion point and refuses to proceed. The check is typeof cfg.insertBefore !== 'string' && typeof cfg.insertAfter !== 'string'.","triggerScenarios":"validateConfig runs on a config missing both 'insertBefore' and 'insertAfter', or where both are set to non-string values (null, undefined, number). Example: {files:[...], commentSyntax:'html'} with no anchor, or insertAfter: null.","commonSituations":"User copies a partial config template that omitted the anchor; renames the key (e.g. 'insertAfterHead') and forgets to update it; sets insertBefore to a RegExp object instead of its source string; deletes the anchor thinking the injector has a default (it does not).","solutions":["Add exactly one anchor as a string: 'insertAfter' set to a literal HTML/JSX fragment like \"<head>\" or 'insertBefore' set to \"</body>\".","If you set both, prefer keeping the single correct one and remove the other to avoid ambiguity (validateConfig allows both being strings but downstream logic prefers one).","Confirm the anchor string actually appears in the target files, otherwise injection silently no-ops."],"exampleFix":"// before\n{\n  \"files\": [\"src/**/*.html\"],\n  \"commentSyntax\": \"html\"\n}\n// after\n{\n  \"files\": [\"src/**/*.html\"],\n  \"insertAfter\": \"<head>\",\n  \"commentSyntax\": \"html\"\n}","handlingStrategy":"validation","validationCode":"const anchor = typeof cfg.insertAfter === 'string' ? cfg.insertAfter\n  : typeof cfg.insertBefore === 'string' ? cfg.insertBefore\n  : null;\nif (!anchor) throw new Error('config needs insertAfter or insertBefore as a string');","typeGuard":"function hasStringAnchor(cfg: any): cfg is { insertAfter: string } | { insertBefore: string } {\n  return typeof cfg?.insertAfter === 'string' || typeof cfg?.insertBefore === 'string';\n}","tryCatchPattern":null,"preventionTips":["Always start from a known-good config template that includes one anchor.","If you support multiple file shapes, generate one config per shape rather than one config with a regex anchor.","Confirm the anchor string literally appears in target files via grep before running injection."],"tags":["config","validation","live-inject","anchor"],"backgroundTag":null,"analyzedSha":"d14711ae3d1a1dd62dee61a358d27f107c51ccd0","analyzedAt":"2026-08-13T00:52:25.771Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}