pbakaus/impeccable · error · Error

config.files (non-empty string array) required

Error message

config.files (non-empty string array) required

What it means

Second validateConfig() check: cfg.files must be a non-empty array. Fires when files is missing, is present but not an array (e.g. a string or object), or is an empty array []. The live-inject flow needs at least one HTML entry point to tag, so an empty list is treated as misconfiguration, not a no-op.

Source

Thrown at plugin/skills/impeccable/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 d14711ae3d)

Solutions

  1. Set config.files to a non-empty array of HTML entry-point paths or globs, e.g. ["index.html", "**\/*.html"].
  2. Re-run the live setup flow to regenerate the config with detected entry points.
  3. If you genuinely want glob discovery, still wrap the pattern in an array: ["src\/**/*.html"].
  4. Validate with `node live-inject.mjs --check` after editing.

Example fix

// before
{ "commentSyntax": "html", "insertBefore": "</head>" }

// after
{
  "files": ["index.html"],
  "commentSyntax": "html",
  "insertBefore": "</head>"
}
Defensive patterns

Strategy: validation

Validate before calling

function hasNonEmptyFiles(cfg) {
  return Array.isArray(cfg?.files) && cfg.files.length > 0;
}
if (!hasNonEmptyFiles(cfg)) {
  throw new Error('config.files must be a non-empty array of paths/globs');
}

Type guard

/** Narrow cfg to one with a usable files array. */
function hasFilesArray(cfg) {
  return cfg != null && typeof cfg === 'object'
    && Array.isArray(cfg.files) && cfg.files.length > 0;
}

Try / catch

try {
  validateConfig(cfg);
} catch (err) {
  if (/config\.files/.test(err.message)) {
    console.error('Fix config.files: ' + err.message);
    // re-run setup to detect entry points
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: config.json has no 'files' key; "files": "index.html" (string not array); "files": [] (empty); "files": {} (object). Each literal entry in files is later treated as a path or glob in resolveFiles(), so the array shape is mandatory.

Common situations: Setup wizard skipped the file-picker step; user deleted all entries thinking inject would auto-detect; mismerged config where 'files' became a single string; glob-only intent but written as a string instead of ["**\/*.html"].

Related errors


AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13). Data as JSON: /api/errors/014f1f46c7f92bce. Report an issue: GitHub.