Egonex-AI/Understand-Anything · error

JSON changed-file list must be an array of strings

Error message

JSON changed-file list must be an array of strings

What it means

parseChangedFileList accepts a changed-files handoff in two formats: a JSON array of path strings, or (legacy) a newline-delimited list. When the content looks like JSON (a .json file or text starting with '[') but the parsed value is not an array, or the array contains non-string elements, this error is thrown rather than silently treating bad data as a file list.

Source

Thrown at understand-anything-plugin/skills/understand/compute-batches.mjs:270

  for (const b of allBatches) {
    for (const f of b.files) m.set(f.path, b.batchIndex);
  }
  return m;
}

function normalizeRelativePathForMatch(pathText) {
  if (typeof pathText !== 'string') return '';
  const platformPath = process.platform === 'win32' ? pathText.replace(/\\/g, '/') : pathText;
  return platformPath
    .replace(/^\.\/+/, '')
    .replace(/\/+/g, '/');
}

function parseChangedFileList(content, filePath) {
  if (filePath.toLowerCase().endsWith('.json') || content.trimStart().startsWith('[')) {
    const parsed = JSON.parse(content);
    if (!Array.isArray(parsed) || parsed.some(path => typeof path !== 'string')) {
      throw new Error('JSON changed-file list must be an array of strings');
    }
    return parsed.map(normalizeRelativePathForMatch).filter(Boolean);
  }
  // Backwards compatibility for existing newline-delimited callers. New
  // incremental handoffs use JSON so embedded newlines remain unambiguous.
  return content.split(/\r?\n/).map(normalizeRelativePathForMatch).filter(Boolean);
}

// ECMAScript string comparison uses a stable UTF-16 code-unit order and does
// not depend on the host locale or ICU version.
function comparePaths(a, b) {
  if (a === b) return 0;
  return a < b ? -1 : 1;
}

/**
 * Returns Map<path, communityId> via Louvain. May throw — caller must catch
 * and fall back if it does. Honors UA_COMPUTE_BATCHES_FORCE_LOUVAIN_THROW=1

View on GitHub (pinned to 07edf82a04)

Solutions

  1. Change the producer to emit a top-level JSON array of path strings, e.g. ["src/a.ts","src/b.ts"] — not an object wrapping the array.
  2. Ensure every element is a string: filter out nulls/numbers before serializing.
  3. If you intended the legacy newline format, remove the leading '[' / .json extension so the newline-delimited path is used.
  4. Validate the JSON with `Array.isArray(parsed) && parsed.every(p => typeof p === 'string')` in the producing script before writing the file.

Example fix

// before (changed-files.json)
{ "changed": ["src/a.ts", 42] }

// after
["src/a.ts", "src/b.ts"]
Defensive patterns

Strategy: validation

Validate before calling

function validateChangedFileList(content) {
  const trimmed = content.trimStart();
  if (trimmed.startsWith('[') || filePath.toLowerCase().endsWith('.json')) {
    const parsed = JSON.parse(content);
    if (!Array.isArray(parsed) || !parsed.every(p => typeof p === 'string')) {
      throw new Error('changed-file list must be a JSON array of path strings');
    }
  }
}

Type guard

function isChangedFileList(value) {
  return Array.isArray(value) && value.every(p => typeof p === 'string');
}

Try / catch

try {
  const changed = parseChangedFileList(content, filePath);
} catch (err) {
  if (err.message.includes('array of strings')) {
    console.error(`${filePath}: expected ["src/a.ts", ...] — got ${describe(content)}`);
    // fall back to regenerating the changed-file list from git diff
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling parseChangedFileList with content that is a JSON object (e.g. `{"files": [...]}`) instead of a bare array; JSON array containing numbers/objects/null entries; content that begins with '[' but is malformed enough to parse into a non-array.

Common situations: An incremental-pipeline step wraps the array in an envelope object instead of emitting a top-level array; a hand-edited JSON file includes numeric statuses mixed with paths; an upstream tool writes `{changed: [...]}`; a diff script writes one JSON object per line.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Egonex-AI/Understand-Anything@07edf82a04 (2026-09-07). Data as JSON: /api/errors/b1554b8516f918af. Report an issue: GitHub.