pbakaus/impeccable · error · Error

config.files (non-empty string array) required

Error message

config.files (non-empty string array) required

What it means

Second check in validateConfig(): cfg.files must be an Array with length > 0. A missing files key, files set to an empty array, or files given as a plain string (a common shorthand mistake) all fail here. This is the list of files the injected script block is written into, so an empty list has nothing to operate on.

Solutions

  1. Set files to a non-empty array of file paths/globs: "files": ["index.html", "src/**/*.html"]
  2. Verify with `node skill/scripts/live-inject.mjs --check` that the parsed files array is non-empty
  3. Ensure the array entries themselves are non-empty strings (the next validation checks that)

Example fix

// before
{ "files": [], "insertAfter": "</title>", "commentSyntax": "html" }

// after
{ "files": ["index.html", "src/**/*.html"], "insertAfter": "</title>", "commentSyntax": "html" }
Defensive patterns

Strategy: validation

Validate before calling

const ok = Array.isArray(cfg.files) && cfg.files.length > 0;
if (!ok) throw new TypeError('config.files must be a non-empty array of path strings');

Type guard

const hasNonEmptyFiles = (cfg) =>
  isInjectConfigObject(cfg) && Array.isArray(cfg.files) && cfg.files.length > 0;

Prevention

When it happens

Trigger: Config omits files entirely; files: []; files: "src/**/*.html" (string instead of array) — note the inject config takes literal paths/globs as array items, not a single string.

Common situations: Converting an example from docs and dropping the brackets; an agent generating the config and leaving files empty because the project layout was unclear; glob strings written before the file list was decided.

Related errors


AI-assisted analysis of pbakaus/impeccable@f88b2837a7 (2026-08-18). Data as JSON: /api/errors/66fe8f5d11265ea6. Report an issue: GitHub.

Appendix: source

Thrown at skill/scripts/live-inject.mjs:452

    } else if (/[.+^${}()|[\]\\]/.test(c)) {
      re += '\\' + c;
      i += 1;
    } else {
      re += c;
      i += 1;
    }
  }
  return new RegExp('^' + re + '$');
}

// ---------------------------------------------------------------------------
// Core operations
// ---------------------------------------------------------------------------

function validateConfig(cfg) {
  if (!cfg || typeof cfg !== 'object') throw new Error('config.json must be an object');
  if (!Array.isArray(cfg.files) || cfg.files.length === 0) {
    throw new Error('config.files (non-empty string array) required');
  }
  if (!cfg.files.every((f) => typeof f === 'string' && f.length > 0)) {
    throw new Error('config.files must contain only non-empty strings');
  }
  if (cfg.exclude !== undefined) {
    if (!Array.isArray(cfg.exclude)) {
      throw new Error('config.exclude, if present, must be a string array');
    }
    if (!cfg.exclude.every((f) => typeof f === 'string' && f.length > 0)) {
      throw new Error('config.exclude must contain only non-empty strings');
    }
  }
  if (typeof cfg.insertBefore !== 'string' && typeof cfg.insertAfter !== 'string') {
    throw new Error('config.insertBefore or config.insertAfter (string) required');
  }
  if (cfg.commentSyntax !== 'html' && cfg.commentSyntax !== 'jsx') {
    throw new Error("config.commentSyntax must be 'html' or 'jsx'");
  }

View on GitHub (pinned to f88b2837a7)