ruvnet/RuView · error · TypeError

args must be an array of strings

Error message

args must be an array of strings

What it means

runProcess() validates that args is an Array and every element is a string, because the array is forwarded directly to spawn with shell:false (no shell tokenization). Any non-array value, including a plain shell-style string, or any non-string element throws this TypeError synchronously before spawn.

Source

Thrown at harness/homecore/src/process-runner.js:100

      }
    }
  }, 2_000);
  force.unref();
  return force;
}

export function runProcess(command, args = [], {
  cwd,
  input = '',
  timeoutMs = 120_000,
  signal,
  maxOutputBytes = 1_048_576,
  env = process.env,
  envAllowlist = DEFAULT_ENV_ALLOWLIST,
} = {}) {
  if (!command || typeof command !== 'string') throw new TypeError('command must be a non-empty string');
  if (!Array.isArray(args) || !args.every((arg) => typeof arg === 'string')) {
    throw new TypeError('args must be an array of strings');
  }
  if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1_000 || timeoutMs > 1_800_000) {
    throw new RangeError('timeoutMs must be a safe integer between 1000 and 1800000');
  }
  if (!Number.isSafeInteger(maxOutputBytes) || maxOutputBytes < 1) {
    throw new RangeError('maxOutputBytes must be a positive safe integer');
  }
  const childEnv = scrubEnvironment(env, envAllowlist);

  return new Promise((resolve, reject) => {
    const child = spawn(command, args, {
      cwd,
      env: childEnv,
      detached: process.platform !== 'win32',
      shell: false,
      windowsHide: true,
      stdio: ['pipe', 'pipe', 'pipe'],
    });

View on GitHub (pinned to 4685618388)

Solutions

  1. Wrap arguments in an array: runProcess('cargo', ['test', '--workspace'])
  2. Coerce computed values with .map(String) before the call
  3. Use a one-element array for a single argument: runProcess('git', ['status'])

Example fix

// before
await runProcess('cargo', 'test --workspace');

// after
await runProcess('cargo', ['test', '--workspace']);
Defensive patterns

Strategy: type-guard

Validate before calling

const isStringArray = (v) => Array.isArray(v) && v.every((a) => typeof a === 'string');
if (!isStringArray(args)) throw new TypeError('args must be an array of strings');

Type guard

/** @param {unknown} v @returns {v is string[]} */
function isArgv(v) {
  return Array.isArray(v) && v.every((a) => typeof a === 'string');
}

Try / catch

try {
  await runProcess(command, args);
} catch (error) {
  if (error instanceof TypeError && error.message.includes('args must be an array')) {
    throw new Error(`expected argv array of strings for ${command}: ${JSON.stringify(args)}`);
  }
  throw error;
}

Prevention

When it happens

Trigger: runProcess('cargo', 'test --workspace') (single string instead of array), runProcess('git', [null]), runProcess('node', [42, '--opt']), or an options object landing in the args position.

Common situations: Habits carried over from exec('cargo test') string APIs, numbers or booleans from parsed JSON config mapped straight into argv, spreading objects into the args slot.

Related errors


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/f92c67896c580f14. Report an issue: GitHub.