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=1View on GitHub (pinned to 07edf82a04)
Solutions
- 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.
- Ensure every element is a string: filter out nulls/numbers before serializing.
- If you intended the legacy newline format, remove the leading '[' / .json extension so the newline-delimited path is used.
- 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
- Emit a top-level JSON array only — never wrap in `{ changed: [...] }`.
- Filter non-string entries (statuses, nulls) before JSON.stringify in the producer.
- Use JSON (not newline-delimited) for any path lists that could contain spaces or newlines.
- Add a CI check that parses every handoff file with the same validator the consumer uses.
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
- Invalid knowledge graph: ${result.fatal ?? "unknown error"}
- Invalid domain graph: ${result.fatal ?? "unknown error"}
- Invalid input: requires { projectRoot: string, filePaths: st
- Invalid input: every files entry must contain a non-empty pa
- Freshness response was malformed
AI-assisted analysis of Egonex-AI/Understand-Anything@07edf82a04 (2026-09-07).
Data as JSON: /api/errors/b1554b8516f918af.
Report an issue: GitHub.