{"record":{"id":"3a421bb7702b5e1b","repo":"decolua/9router","slug":"item-is-not-an-object","errorCode":null,"errorMessage":"Item is not an object","messagePattern":"Item is not an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/app/api/oauth/codex/bulk-import/route.js","lineNumber":59,"sourceCode":"\n  if (!Array.isArray(accounts) || accounts.length === 0) {\n    return NextResponse.json(\n      { error: \"No accounts provided\" },\n      { status: 400 }\n    );\n  }\n\n  const results = [];\n  let success = 0;\n  let failed = 0;\n\n  // SERIAL loop — createProviderConnection reads max(priority) and reorders\n  // inside a transaction. Parallel calls would race on priority assignment.\n  for (let i = 0; i < accounts.length; i++) {\n    const raw = accounts[i];\n    try {\n      if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n        throw new Error(\"Item is not an object\");\n      }\n\n      // Strip server-controlled fields\n      const {\n        id: _id,\n        provider: _provider,\n        authType: _authType,\n        createdAt: _createdAt,\n        updatedAt: _updatedAt,\n        ...item\n      } = raw;\n\n      if (!item.accessToken || typeof item.accessToken !== \"string\") {\n        throw new Error(\"Missing accessToken\");\n      }\n\n      // Backfill missing identity fields from JWT claims\n      const psd = item.providerSpecificData || {};","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/app/api/oauth/codex/bulk-import/route.js#L41-L77","documentation":"The codex bulk-import route iterates the accounts array and validates each entry: it must be a non-null, non-array object. Anything else (null, string, number, array) throws 'Item is not an object'; the error is caught per-item and counted as a failure rather than aborting the whole import.","triggerScenarios":"POSTing to /api/oauth/codex/bulk-import with accounts containing null, a string (e.g. a raw token instead of an object), an array, or a number at one of the positions.","commonSituations":"Pasting a JSON array of token strings instead of objects, exporting from another tool with a different shape, a trailing comma producing null in hand-edited JSON, or a shell tool mangling the payload.","solutions":["Ensure every element of accounts is a JSON object like {\"accessToken\": \"...\", ...}.","Remove null/placeholder entries from the array before importing.","If you have bare token strings, wrap each in an object: { accessToken: token }."],"exampleFix":"// before\n{ \"accounts\": [\"eyJhbGciOi...\", null] }\n// after\n{ \"accounts\": [{ \"accessToken\": \"eyJhbGciOi...\" }] }","handlingStrategy":"type-guard","validationCode":"const bad = accounts.findIndex(\n  (a) => !a || typeof a !== \"object\" || Array.isArray(a)\n);\nif (bad !== -1) console.error(`accounts[${bad}] is not an object`);","typeGuard":"const isImportItem = (x) =>\n  x !== null && typeof x === \"object\" && !Array.isArray(x);","tryCatchPattern":"try {\n  const res = await bulkImport(accounts);\n} catch (e) {\n  if (e.message === \"Item is not an object\") {\n    console.error(\"Filter accounts to plain objects and retry\");\n  } else throw e;\n}","preventionTips":["Export/import JSON arrays of objects, never raw token strings","Remove null placeholders from hand-edited JSON arrays","Pre-validate the payload shape client-side before POSTing"],"tags":["validation","bulk-import","codex"],"backgroundTag":"schema-validation-failed","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}