affaan-m/ECC · error · Error

orch-review: args.changedFiles must contain only string…

Error message

orch-review: args.changedFiles must contain only string paths

What it means

Even when changedFiles is an array, every entry must be a plain string path. A non-string entry (e.g. { path: '...' } object or a number) would stringify to "[object Object]" and poison the security-trigger haystack, so the workflow fails closed rather than reviewing corrupted input.

Solutions

  1. Map entries to strings before invoking: changedFiles.map(f => typeof f === 'string' ? f : f.path).
  2. Validate the producer output shape and normalize to string paths at the boundary.
  3. Add a caller-side check `files.every(f => typeof f === 'string')` before invoking the workflow.

Example fix

// before
review({ diff, changedFiles: githubFiles }); // [{ filename: 'a.js' }]
// after
review({ diff, changedFiles: githubFiles.map(f => f.filename) });
Defensive patterns

Strategy: type-guard

Validate before calling

const files = (githubFiles ?? []).map(f => typeof f === 'string' ? f : f.filename);
if (!files.every(f => typeof f === 'string')) {
  throw new Error('changedFiles entries must be string paths');
}

Type guard

const isStringPathArray = v => Array.isArray(v) && v.every(f => typeof f === 'string');

Try / catch

try {
  const result = await orchReview({ diff, changedFiles: files });
} catch (err) {
  if (err.message.includes('must contain only string paths')) {
    console.error('Map file objects to their .filename/.path before invoking.');
  } else throw err;
}

Prevention

When it happens

Trigger: Calling with { diff: '...', changedFiles: [{ path: 'a.js' }] } or changedFiles: [1, 2] — the array check passes but changedFiles.every(f => typeof f === 'string') fails.

Common situations: Passing file objects straight from a VCS/API client (GitHub files API returns { filename, status } objects); including line-number metadata tuples; mixing parsed diff entries with raw path strings.

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 affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/7565305b15ae2f5b. Report an issue: GitHub.

Appendix: source

Thrown at workflows/orch-review.workflow.js:171

try {
  input = typeof args === 'string' ? JSON.parse(args) : (args ?? {});
} catch {
  throw new Error('orch-review: args must be an object or valid JSON');
}
if (typeof input !== 'object' || input === null) {
  throw new Error('orch-review: args must be an object');
}
if (typeof input.diff !== 'string' || input.diff.trim() === '') {
  throw new Error('orch-review: args.diff must be a non-empty unified diff');
}
if (input.changedFiles != null && !Array.isArray(input.changedFiles)) {
  throw new Error('orch-review: args.changedFiles must be an array of paths');
}
// Every entry must be a string path. A non-string (e.g. { path: '...' }) would
// stringify to "[object Object]" and silently poison the security-trigger
// haystack — fail closed on malformed input instead.
if (Array.isArray(input.changedFiles) && !input.changedFiles.every(f => typeof f === 'string')) {
  throw new Error('orch-review: args.changedFiles must contain only string paths');
}

const diff = input.diff;
const haystack = `${diff}\n${(input.changedFiles || []).join('\n')}`;

// Build the review dimensions immutably. Quality always runs; language +
// security are conditional, spread in rather than pushed onto a shared array.
const langReviewer = input.language && LANGUAGE_REVIEWER[String(input.language).toLowerCase()];
const securityNeeded = SECURITY_TRIGGER.test(haystack);
const dimensions = [
  { key: 'quality', label: 'correctness & quality', agentType: 'ecc:code-reviewer' },
  ...(langReviewer ? [{ key: `lang:${input.language}`, label: `${input.language} idioms & pitfalls`, agentType: langReviewer }] : []),
  ...(securityNeeded ? [{ key: 'security', label: 'security (OWASP, secrets, injection)', agentType: 'ecc:security-reviewer' }] : [])
];
if (securityNeeded) {
  log('Security trigger matched — adding security-reviewer dimension.');
}

View on GitHub (pinned to 8321021c54)