{"record":{"id":"47522bd55af7ca34","repo":"jackwener/OpenCLI","slug":"label-must-be-a-path-url-or-a-json-array-err","errorCode":null,"errorMessage":"${label} must be a path/URL or a JSON array: ${errorMessage(error)}","messagePattern":"(.+?) must be a path/URL or a JSON array: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/midjourney/utils.js","lineNumber":870,"sourceCode":"  const usedMinutes = creditsToFastMinutes(Number(last.periodCreditsUsed) - Number(first.periodCreditsUsed));\n  if (!(elapsedDays >= 1) || !(usedMinutes > 0)) return { avgDailyMinutes: null, projectedExhaustionDate: null };\n  const avgDailyMinutes = Number((usedMinutes / elapsedDays).toFixed(2));\n  const remainingMinutes = creditsToFastMinutes(account?.total_credits ?? account?.credits_total);\n  const projected = remainingMinutes > 0\n    ? new Date(Date.now() + (remainingMinutes / avgDailyMinutes) * 86_400_000).toISOString()\n    : null;\n  return { avgDailyMinutes, projectedExhaustionDate: projected };\n}\n\nexport function parseReferenceArgument(value, label, { multiple = true, allowStyleCode = false } = {}) {\n  if (value == null || value === '') return [];\n  let items;\n  const raw = String(value).trim();\n  if (raw.startsWith('[')) {\n    try {\n      items = JSON.parse(raw);\n    } catch (error) {\n      throw new ArgumentError(`${label} must be a path/URL or a JSON array: ${errorMessage(error)}`);\n    }\n  } else {\n    items = [raw];\n  }\n  if (!Array.isArray(items) || items.length === 0 || items.some((item) => typeof item !== 'string' || !item.trim())) {\n    throw new ArgumentError(`${label} must contain one or more non-empty strings`);\n  }\n  if (!multiple && items.length !== 1) throw new ArgumentError(`${label} accepts exactly one reference`);\n  return items.map((item) => item.trim()).map((item) => {\n    if (allowStyleCode && /^\\d+$/.test(item)) return { kind: 'styleCode', value: item };\n    if (/^https:\\/\\//i.test(item)) {\n      try {\n        const parsed = new URL(item);\n        const match = parsed.hostname === MIDJOURNEY_DOMAIN\n          ? parsed.pathname.match(/^\\/jobs\\/([0-9a-f-]{36})\\/?$/i)\n          : null;\n        if (match && UUID_RE.test(match[1])) {\n          const index = Number(parsed.searchParams.get('index') || 0);","sourceCodeStart":852,"sourceCodeEnd":888,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/midjourney/utils.js#L852-L888","documentation":"An ArgumentError raised when a value that starts with '[' is treated as a JSON array but JSON.parse fails. The parsePoints-style helper accepts either a path/URL string or a literal JSON array; malformed JSON in the array form is wrapped with the underlying parse error message to help the caller fix their input.","triggerScenarios":"Passing a string beginning with '[' that is not valid JSON — e.g. \"[a, b]\" (unquoted items), a truncated array, or single-quoted JSON \"['x','y']\". Note a value merely containing brackets but not starting with '[' is treated as a path/URL instead.","commonSituations":"Hand-writing JSON arrays with unquoted strings or trailing commas; shell quoting stripping double quotes so '[\"a\"]' becomes [a]; copying a JS array literal into config; empty arrays passed where at least one item is required (that case hits the sibling 'must contain one or more non-empty strings' error).","solutions":["Fix the JSON so it parses: quote all strings with double quotes and remove trailing commas (e.g. [\"img1.png\",\"img2.png\"])","Validate the JSON first (JSON.parse in a REPL or a JSON linter) before passing it","If you meant a file/URL, ensure the value does not start with '[' — otherwise it is parsed as JSON","In shells, single-quote the argument: --points '[\"a.png\",\"b.png\"]' to prevent quote stripping","If items come from another tool, serialize with JSON.stringify rather than string interpolation"],"exampleFix":"// before\n--prompts \"['cat', 'dog']\"          // single quotes -> JSON.parse fails\n// after\n--prompts '[\"cat\", \"dog\"]'          // valid JSON array","handlingStrategy":"validation","validationCode":"function parseItemList(value, label) {\n  const raw = String(value).trim();\n  if (raw.startsWith('[')) {\n    const items = JSON.parse(raw); // throws SyntaxError early with position info\n    if (!Array.isArray(items) || items.length === 0 || items.some((i) => typeof i !== 'string' || !i.trim())) {\n      throw new TypeError(`${label} must contain one or more non-empty strings`);\n    }\n    return items;\n  }\n  return [raw];\n}\nconst items = parseItemList(cliArg, 'Images');","typeGuard":null,"tryCatchPattern":"try {\n  await midjourney.run({ prompts: rawArg });\n} catch (err) {\n  if (err.name === 'ArgumentError' && err.message.includes('JSON array')) {\n    console.error(`Invalid JSON: ${err.message}. Double-quote strings and single-quote the whole arg in shells.`);\n  } else throw err;\n}","preventionTips":["Always serialize lists with JSON.stringify, never hand-write or interpolate them","In shells, wrap JSON args in single quotes to prevent double-quote stripping","Validate JSON input with a linter or JSON.parse dry-run before invoking the CLI","Remember: values not starting with '[' are treated as a single path/URL, not an array"],"tags":["argument-error","json-parse","validation","cli-input"],"backgroundTag":"json-parse-error","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}