{"record":{"id":"86a25c422c1c0a26","repo":"can1357/oh-my-pi","slug":"unable-to-read-omp-auth-broker-account-pool-file-a","errorCode":null,"errorMessage":"Unable to read OMP_AUTH_BROKER_ACCOUNT_POOL_FILE at ${filePath}","messagePattern":"Unable to read OMP_AUTH_BROKER_ACCOUNT_POOL_FILE at (.+?)","errorType":"exception","errorClass":"AIError.ConfigurationError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/auth-broker/discover.ts","lineNumber":126,"sourceCode":"\t\t\treturn { url, token };\n\t\t} catch (err) {\n\t\t\tif (isEnoent(err)) continue;\n\t\t\tlogger.warn(\"auth-broker config unreadable\", { path: configPath, error: String(err) });\n\t\t\treturn {};\n\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}","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/auth-broker/discover.ts#L108-L144","documentation":"loadAuthBrokerAccountPool reads the account pool file pointed to by OMP_AUTH_BROKER_ACCOUNT_POOL_FILE. If Bun.file(filePath).json() fails for any reason — missing file, permission denied, invalid JSON, unreadable path — it rethrows as AIError.ConfigurationError with the path embedded and the original error as cause. The library treats an unreadable pool file as fatal configuration rather than silently disabling the pool, because a partially-working auth broker setup is worse than a clear startup failure.","triggerScenarios":"Calling loadAuthBrokerAccountPool (directly or via accountPool) when OMP_AUTH_BROKER_ACCOUNT_POOL_FILE is set to a path that does not exist, points to a directory, has wrong permissions, or contains non-JSON content.","commonSituations":"Typo in the file path; file deleted or moved after export; pool file generated by another tool that wrote invalid JSON (trailing commas, truncation); relative path resolved from a different working directory in a daemon/systemd context; read permissions changed by a security policy.","solutions":["Verify the file exists and is readable: `cat \"$OMP_AUTH_BROKER_ACCOUNT_POOL_FILE\" > /dev/null && echo ok` (or ls -l the path).","Validate the file is well-formed JSON: `jq . \"$OMP_AUTH_BROKER_ACCOUNT_POOL_FILE\"` and fix any parse errors.","If using a relative path, switch to an absolute path so the process's cwd cannot change the resolution.","If the pool is optional for your setup, unset OMP_AUTH_BROKER_ACCOUNT_POOL_FILE entirely (empty/undefined disables the pool).","Inspect the `cause` property of the thrown ConfigurationError to distinguish ENOENT vs EACCES vs JSON parse failure."],"exampleFix":"// before\nexport OMP_AUTH_BROKER_ACCOUNT_POOL_FILE=./pool.json   # relative, file may not exist\n\n// after\nexport OMP_AUTH_BROKER_ACCOUNT_POOL_FILE=/etc/omp/account-pool.json   # absolute, verified with jq","handlingStrategy":"try-catch","validationCode":"// before calling the API\nconst filePath = process.env.OMP_AUTH_BROKER_ACCOUNT_POOL_FILE?.trim();\nif (filePath) {\n  const file = Bun.file(filePath);\n  if (!(await file.exists())) throw new Error(`pool file missing: ${filePath}`);\n  JSON.parse(await file.text()); // throws SyntaxError with details if not valid JSON\n}","typeGuard":"function isReadableFile(p: string): boolean {\n  try {\n    return fs.statSync(p).isFile();\n  } catch {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  const pool = await loadAuthBrokerAccountPool();\n} catch (err) {\n  if (err instanceof AIError.ConfigurationError && err.message.includes(\"Unable to read OMP_AUTH_BROKER_ACCOUNT_POOL_FILE\")) {\n    logger.error(\"account pool file unreadable\", { cause: err.cause });\n    // fall back to no pool or abort startup\n  } else throw err;\n}","preventionTips":["Use absolute paths for OMP_AUTH_BROKER_ACCOUNT_POOL_FILE so cwd changes cannot break resolution.","Validate the file with `jq . \"$VAR\"` at deploy time before the service starts.","In provisioning scripts, fail fast if the pool file is missing after creation.","Remember: unsetting the env var cleanly disables the pool — don't leave it pointing at a removed file."],"tags":["configuration","filesystem","auth-broker","startup"],"backgroundTag":"config-file-unreadable","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}