{"record":{"id":"1f38ea51020deb33","repo":"decolua/9router","slug":"input-must-be-a-json-object-or-array-of-objects","errorCode":null,"errorMessage":"Input must be a JSON object or array of objects","messagePattern":"Input must be a JSON object or array of objects","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/app/(dashboard)/dashboard/providers/[id]/BulkImportGrokCliModal.js","lineNumber":52,"sourceCode":"        fixed = fixed.replace(/\\}\\s*,\\s*\\{/g, \"},{\").replace(/\\}\\s*\\{/g, \"},{\");\n        if (fixed.endsWith(\",\")) fixed = fixed.slice(0, -1);\n        fixed = `[${fixed}]`;\n      }\n      parsed = JSON.parse(fixed);\n    } catch {\n      throw initialErr;\n    }\n  }\n\n  if (Array.isArray(parsed)) {\n    return parsed;\n  }\n  if (parsed && typeof parsed === \"object\") {\n    if (Array.isArray(parsed.accounts)) return parsed.accounts;\n    return [parsed];\n  }\n\n  throw new Error(\"Input must be a JSON object or array of objects\");\n}\n\nexport default function BulkImportGrokCliModal({ isOpen, onClose, onSuccess }) {\n  const [jsonText, setJsonText] = useState(\"\");\n  const [submitting, setSubmitting] = useState(false);\n  const [parseError, setParseError] = useState(\"\");\n  const [result, setResult] = useState(null);\n  const [isDragging, setIsDragging] = useState(false);\n  const [fileCountInfo, setFileCountInfo] = useState(null);\n  const fileInputRef = useRef(null);\n\n  const handleClose = () => {\n    if (submitting) return;\n    setJsonText(\"\");\n    setParseError(\"\");\n    setResult(null);\n    setFileCountInfo(null);\n    setIsDragging(false);","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/app/(dashboard)/dashboard/providers/[id]/BulkImportGrokCliModal.js#L34-L70","documentation":"parseAccountsInput in BulkImportGrokCliModal throws this after JSON.parse succeeds but the value is neither an object containing an `accounts` array nor a bare object. It guards the accepted bulk-import shapes for Grok CLI accounts.","triggerScenarios":"Pasting JSON that parses to a primitive (string, number, true/false/null) — parsed is truthy but typeof !== 'object'; note `null` passes JSON.parse but typeof null === 'object' with Array.isArray(null) false, so [null] path is not hit and null itself reaches... actually null is excluded earlier by `parsed &&`, so the throw fires for any truthy non-object or when an empty/odd top-level shape arrives.","commonSituations":"User pastes a quoted JSON string (\"…\" parses to a string), a bare number, `true`, or a JSONL file with multiple lines that isn't valid single-document JSON; copies the inner value of an export instead of the wrapper object.","solutions":["Wrap the account object in an array: [{...}] or {\"accounts\": [...]}\nRemove surrounding quotes if the whole input is a JSON-encoded string\nIf importing JSONL (one object per line), convert to a JSON array first\nTrim trailing commas/comments that make JSON.parse produce unexpected types"],"exampleFix":"// before\nthrow new Error(\"Input must be a JSON object or array of objects\");\n// after — accept arrays at top level too\nif (Array.isArray(parsed)) return parsed;\nif (parsed && typeof parsed === \"object\") {\n  if (Array.isArray(parsed.accounts)) return parsed.accounts;\n  return [parsed];\n}\nthrow new Error(\"Input must be a JSON object or array of objects\");","handlingStrategy":"validation","validationCode":"function parseAccountsInput(text) {\n  const parsed = JSON.parse(text);\n  if (Array.isArray(parsed)) return parsed;\n  if (parsed && typeof parsed === \"object\" && Array.isArray(parsed.accounts)) return parsed.accounts;\n  if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return [parsed];\n  throw new Error(\"Input must be a JSON object or array of objects\");\n}","typeGuard":"function isAccountShape(v) {\n  return v !== null && typeof v === \"object\" && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  const accounts = parseAccountsInput(jsonText);\n  setParseError(\"\");\n  await submit(accounts);\n} catch (err) {\n  setParseError(err.message);\n}","preventionTips":["Paste a top-level array [{...}] or an object with an accounts key","Avoid pasting a JSON-encoded string (double-encoded) — check for leading quotes","Convert JSONL input into a single JSON array first","Preview parsed account count in the UI before submit"],"tags":["validation","json","parsing","bulk-import"],"backgroundTag":"invalid-json-input","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}