{"record":{"id":"f92c67896c580f14","repo":"ruvnet/RuView","slug":"args-must-be-an-array-of-strings","errorCode":null,"errorMessage":"args must be an array of strings","messagePattern":"args must be an array of strings","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"harness/homecore/src/process-runner.js","lineNumber":100,"sourceCode":"      }\n    }\n  }, 2_000);\n  force.unref();\n  return force;\n}\n\nexport function runProcess(command, args = [], {\n  cwd,\n  input = '',\n  timeoutMs = 120_000,\n  signal,\n  maxOutputBytes = 1_048_576,\n  env = process.env,\n  envAllowlist = DEFAULT_ENV_ALLOWLIST,\n} = {}) {\n  if (!command || typeof command !== 'string') throw new TypeError('command must be a non-empty string');\n  if (!Array.isArray(args) || !args.every((arg) => typeof arg === 'string')) {\n    throw new TypeError('args must be an array of strings');\n  }\n  if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1_000 || timeoutMs > 1_800_000) {\n    throw new RangeError('timeoutMs must be a safe integer between 1000 and 1800000');\n  }\n  if (!Number.isSafeInteger(maxOutputBytes) || maxOutputBytes < 1) {\n    throw new RangeError('maxOutputBytes must be a positive safe integer');\n  }\n  const childEnv = scrubEnvironment(env, envAllowlist);\n\n  return new Promise((resolve, reject) => {\n    const child = spawn(command, args, {\n      cwd,\n      env: childEnv,\n      detached: process.platform !== 'win32',\n      shell: false,\n      windowsHide: true,\n      stdio: ['pipe', 'pipe', 'pipe'],\n    });","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/harness/homecore/src/process-runner.js#L82-L118","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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'])"],"exampleFix":"// before\nawait runProcess('cargo', 'test --workspace');\n\n// after\nawait runProcess('cargo', ['test', '--workspace']);","handlingStrategy":"type-guard","validationCode":"const isStringArray = (v) => Array.isArray(v) && v.every((a) => typeof a === 'string');\nif (!isStringArray(args)) throw new TypeError('args must be an array of strings');","typeGuard":"/** @param {unknown} v @returns {v is string[]} */\nfunction isArgv(v) {\n  return Array.isArray(v) && v.every((a) => typeof a === 'string');\n}","tryCatchPattern":"try {\n  await runProcess(command, args);\n} catch (error) {\n  if (error instanceof TypeError && error.message.includes('args must be an array')) {\n    throw new Error(`expected argv array of strings for ${command}: ${JSON.stringify(args)}`);\n  }\n  throw error;\n}","preventionTips":["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"],"tags":["validation","process","typeerror","argv"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}