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
- Wrap arguments in an array: runProcess('cargo', ['test', '--workspace'])
- Coerce computed values with .map(String) before the call
- 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
- Always author argv as an array literal, never a shell-style string
- Coerce config-sourced values with .map(String) before passing
- shell is false in this runner — no shell parsing happens, so each token must be its own array element
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
- command must be a non-empty string
- timeoutMs must be a safe integer between 1000 and 1800000
- maxOutputBytes must be a positive safe integer
- repoRoot and trustedRoot are required
- guidance input must be an object
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/f92c67896c580f14.
Report an issue: GitHub.