{"record":{"id":"6b6f7d3cc602eae0","repo":"tinyhumansai/openhuman","slug":"openai-codex-oauth-missing-auth-url","errorCode":"OPENAI_CODEX_OAUTH_MISSING_AUTH_URL","errorMessage":"OPENAI_CODEX_OAUTH_MISSING_AUTH_URL","messagePattern":"OPENAI_CODEX_OAUTH_MISSING_AUTH_URL","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/services/api/aiSettingsApi.ts","lineNumber":726,"sourceCode":"\n/** Clear a stored API key. */\nexport async function clearCloudProviderKey(slug: string): Promise<void> {\n  if (slug === 'openhuman') {\n    return;\n  }\n  // Clear the new-style key. Legacy bare-slug entries are left as-is\n  // since we can't be sure they aren't used by other things.\n  await authRemoveProviderCredentials({ provider: authKeyForSlug(slug), profile: 'default' });\n}\n\nexport async function startOpenAiCodexOAuth(): Promise<OpenAiCodexOAuthStartResult> {\n  const res = await callCoreRpc<{ result: OpenAiCodexOAuthStartResult }>({\n    method: 'openhuman.inference_openai_oauth_start',\n    params: {},\n  });\n  const authUrl = res?.result?.authUrl?.trim();\n  if (!authUrl) {\n    throw new Error(OPENAI_CODEX_OAUTH_MISSING_AUTH_URL);\n  }\n  return res.result;\n}\n\nexport async function completeOpenAiCodexOAuth(callbackUrl: string): Promise<void> {\n  const callback = callbackUrl.trim();\n  if (!callback) {\n    throw new Error(OPENAI_CODEX_OAUTH_MISSING_CALLBACK_URL);\n  }\n  await callCoreRpc({\n    method: 'openhuman.inference_openai_oauth_complete',\n    params: { callback_url: callback },\n  });\n}\n\nexport async function importOpenAiCodexCliAuth(): Promise<void> {\n  await callCoreRpc({ method: 'openhuman.inference_openai_oauth_import_codex_cli', params: {} });\n}","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/services/api/aiSettingsApi.ts#L708-L744","documentation":"Thrown by startOpenAiCodexOAuth() after the core RPC 'openhuman.inference_openai_oauth_start' resolves but the result's authUrl field is missing, empty, or whitespace-only after trimming. The OpenHuman Rust core is expected to build a ChatGPT/OpenAI OAuth authorize URL (from its client-id config) and return it for an external-browser flow; this guard catches a core that answered the RPC without producing one. It is a client-side contract check, not a network error — the RPC itself succeeded.","triggerScenarios":"Calling startOpenAiCodexOAuth() when: the core's Codex OAuth client credentials are unset or malformed; the core version predates inference_openai_oauth_start returning auth_url; the core handler hit an internal config error and returned an empty result object instead of an RPC error.","commonSituations":"Fresh desktop install where the backend/api config block is incomplete; running the UI against an older or standalone core binary (openhuman-core serve) that lacks the OAuth start handler's full response; a config migration wiped provider OAuth settings; environment (.env) missing required OAuth variables the core reads at startup.","solutions":["Check the core log output for the inference/OAuth start handler — it usually logs why no authUrl was built (missing client id / endpoint config).","Verify your core is current: the UI and openhuman-core must be from the same release; restart or update the core (restartCoreProcess or reinstall) so inference_openai_oauth_start returns auth_url.","Confirm the Codex/OpenAI OAuth settings exist in Settings > AI providers, or that the .env / config TOML the core loads has the OAuth client values it needs.","If running a standalone core (openhuman-core serve), point the app at the matching version or run the bundled desktop core instead."],"exampleFix":"// before\nconst res = await callCoreRpc<{ result: OpenAiCodexOAuthStartResult }>({\n  method: 'openhuman.inference_openai_oauth_start',\n  params: {},\n});\nconst authUrl = res?.result?.authUrl?.trim();\nif (!authUrl) {\n  throw new Error(OPENAI_CODEX_OAUTH_MISSING_AUTH_URL);\n}\n\n// after — surface the raw core result to make triage possible\nif (!authUrl) {\n  throw new Error(\n    `${OPENAI_CODEX_OAUTH_MISSING_AUTH_URL} (core result: ${JSON.stringify(res?.result ?? null)})`\n  );\n}","handlingStrategy":"try-catch","validationCode":"import { callCoreRpc } from '../coreRpcClient';\n\nasync function canStartCodexOAuth(): Promise<boolean> {\n  try {\n    const res = await callCoreRpc<{ result?: { authUrl?: string } }>({\n      method: 'openhuman.inference_openai_oauth_start',\n      params: {},\n    });\n    return Boolean(res?.result?.authUrl?.trim());\n  } catch {\n    return false;\n  }\n}","typeGuard":"function hasAuthUrl(res: unknown): res is { authUrl: string } {\n  return typeof (res as { authUrl?: unknown })?.authUrl === 'string'\n    && (res as { authUrl: string }).authUrl.trim().length > 0;\n}","tryCatchPattern":"try {\n  const { authUrl } = await startOpenAiCodexOAuth();\n  await openExternal(authUrl);\n} catch (e) {\n  if (e instanceof Error && e.message === 'OPENAI_CODEX_OAUTH_MISSING_AUTH_URL') {\n    notify('Could not start Codex sign-in — update/restart the Core and retry.');\n  } else throw e;\n}","preventionTips":["Keep app UI and openhuman-core on the same release; restart the core after updates.","Surface the raw core result in the error message during development for fast triage.","Verify OAuth client config (env/TOML) before shipping a settings screen that calls the flow."],"tags":["oauth","core-rpc","codex","config","response-validation"],"backgroundTag":"oauth-missing-auth-url","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}