{"record":{"id":"2bb0dea876601238","repo":"can1357/oh-my-pi","slug":"omp-auth-broker-account-pool-file-must-contain-a-j","errorCode":null,"errorMessage":"OMP_AUTH_BROKER_ACCOUNT_POOL_FILE must contain a JSON object","messagePattern":"OMP_AUTH_BROKER_ACCOUNT_POOL_FILE must contain a JSON object","errorType":"validation","errorClass":"AIError.ConfigurationError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/auth-broker/discover.ts","lineNumber":131,"sourceCode":"\t\t}\n\t}\n\treturn {};\n}\n\nexport async function loadAuthBrokerAccountPool(): Promise<AuthBrokerAccountPool | undefined> {\n\tconst filePath = process.env.OMP_AUTH_BROKER_ACCOUNT_POOL_FILE?.trim();\n\tif (!filePath) return undefined;\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = await Bun.file(filePath).json();\n\t} catch (error) {\n\t\tthrow new AIError.ConfigurationError(`Unable to read OMP_AUTH_BROKER_ACCOUNT_POOL_FILE at ${filePath}`, {\n\t\t\tcause: error,\n\t\t});\n\t}\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new AIError.ConfigurationError(\"OMP_AUTH_BROKER_ACCOUNT_POOL_FILE must contain a JSON object\");\n\t}\n\n\tconst accountPool = new Map<string, ReadonlySet<string>>();\n\tfor (const [provider, value] of Object.entries(parsed)) {\n\t\tconst normalizedProvider = provider.trim();\n\t\tif (normalizedProvider.length === 0) {\n\t\t\tthrow new AIError.ConfigurationError(\"OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains an empty provider id\");\n\t\t}\n\t\tif (provider !== normalizedProvider) {\n\t\t\tthrow new AIError.ConfigurationError(\n\t\t\t\t\"OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains a provider id with surrounding whitespace\",\n\t\t\t);\n\t\t}\n\t\tif (!Array.isArray(value)) {\n\t\t\tthrow new AIError.ConfigurationError(\n\t\t\t\t`OMP_AUTH_BROKER_ACCOUNT_POOL_FILE entry for ${provider} must be an array of identity keys`,\n\t\t\t);\n\t\t}","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/auth-broker/discover.ts#L113-L149","documentation":"After the pool file is successfully parsed, loadAuthBrokerAccountPool validates its shape: it must be a non-null, non-array JSON object whose keys are provider ids and whose values are identity-key arrays. A file containing a bare string, number, boolean, null, or a JSON array is rejected with this ConfigurationError, since the loader needs an object to map providers to identity sets.","triggerScenarios":"OMP_AUTH_BROKER_ACCOUNT_POOL_FILE points to a file whose top-level JSON is null, a scalar (\"abc\", 42, true), or an array (e.g. a JSON list of accounts instead of an object keyed by provider).","commonSituations":"Pool file written by a script exporting an array of provider entries instead of an object; hand-written placeholder containing null or \"todo\"; a tool that serialized a Map as an array of [key, value] pairs.","solutions":["Reshape the file to a top-level JSON object: { \"provider-id\": [\"identity-key\", ...] }.","If your data is currently an array, convert it (e.g. Object.fromEntries(entries.map(e => [e.provider, e.identities]))).","Check the generating script/writer to ensure it serializes the object form, and validate with `jq 'type' file` — it must print \"object\".","If the file is a placeholder, remove the env var until a real pool file is produced."],"exampleFix":"// before (account-pool.json)\n[\"openai:acc1\", \"anthropic:acc2\"]\n\n// after\n{\n  \"openai\": [\"acc1\"],\n  \"anthropic\": [\"acc2\"]\n}","handlingStrategy":"validation","validationCode":"function validatePoolFileShape(text: string): void {\n  const parsed = JSON.parse(text);\n  if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n    throw new Error(\"pool file must be a top-level JSON object keyed by provider\");\n  }\n}","typeGuard":"function isProviderPool(v: unknown): v is Record<string, unknown> {\n  return v !== null && typeof v === \"object\" && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  const pool = await loadAuthBrokerAccountPool();\n} catch (err) {\n  if (err instanceof AIError.ConfigurationError && err.message.includes(\"must contain a JSON object\")) {\n    logger.error(\"pool file top-level shape invalid; expected object keyed by provider\");\n  } else throw err;\n}","preventionTips":["Keep a canonical example pool file in your repo and validate against it in CI.","Have writer scripts assert the serialized top level is an object before writing.","Check with `jq 'type' pool.json` — must output \"object\".","Never hand-edit the pool file without re-running your JSON validation step."],"tags":["configuration","json","schema-validation","auth-broker"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}