tinyhumansai/openhuman · error
OPENAI_CODEX_OAUTH_MISSING_CALLBACK_URL
OPENAI_CODEX_OAUTH_MISSING_CALLBACK_URL
Error message
OPENAI_CODEX_OAUTH_MISSING_CALLBACK_URL
What it means
completeOpenAiCodexOAuth requires the OAuth callback URL (the deep link the browser redirected back to, containing the code/state query). After trimming, an empty value cannot be exchanged for tokens, so the client rejects it before calling openhuman.inference_openai_oauth_complete.
Source
Thrown at app/src/services/api/aiSettingsApi.ts:734
await authRemoveProviderCredentials({ provider: authKeyForSlug(slug), profile: 'default' });
}
export async function startOpenAiCodexOAuth(): Promise<OpenAiCodexOAuthStartResult> {
const res = await callCoreRpc<{ result: OpenAiCodexOAuthStartResult }>({
method: 'openhuman.inference_openai_oauth_start',
params: {},
});
const authUrl = res?.result?.authUrl?.trim();
if (!authUrl) {
throw new Error(OPENAI_CODEX_OAUTH_MISSING_AUTH_URL);
}
return res.result;
}
export async function completeOpenAiCodexOAuth(callbackUrl: string): Promise<void> {
const callback = callbackUrl.trim();
if (!callback) {
throw new Error(OPENAI_CODEX_OAUTH_MISSING_CALLBACK_URL);
}
await callCoreRpc({
method: 'openhuman.inference_openai_oauth_complete',
params: { callback_url: callback },
});
}
export async function importOpenAiCodexCliAuth(): Promise<void> {
await callCoreRpc({ method: 'openhuman.inference_openai_oauth_import_codex_cli', params: {} });
}
/**
* Eagerly write the cloud_providers list to the core config.
*
* Called immediately when providers are added/edited/removed so that
* `listProviderModels` can resolve the provider by id without waiting for
* the user to click the global Save button. API keys are NOT included here
* (they're written via `setCloudProviderKey` on their own path).View on GitHub (pinned to a221052e0d)
Solutions
- Capture the full callback URL from the deep-link event and pass it through unmodified
- Guard the handler: if the trimmed URL is empty, ignore the event (it may be an unrelated scheme invocation)
- Verify the redirect URI configured in the OAuth app matches the deep link so the full URL survives
Example fix
// before
onDeepLink(url => completeOpenAiCodexOAuth(extractPath(url)));
// after
onDeepLink(url => {
const callback = url?.trim();
if (!callback) return; // unrelated or incomplete invocation
completeOpenAiCodexOAuth(callback).catch(notify);
}); Defensive patterns
Strategy: validation
Validate before calling
const callback = typeof callbackUrl === 'string' ? callbackUrl.trim() : ''; if (callback) await completeOpenAiCodexOAuth(callback);
Type guard
const isNonEmptyTrimmed = (v: unknown): v is string => typeof v === 'string' && v.trim().length > 0;
Try / catch
try { await completeOpenAiCodexOAuth(callbackUrl); }
catch (e) { if (String(e.message).includes('callback')) restartOAuthFlow(); else throw e; } Prevention
- Pass the deep-link URL through verbatim — don't re-parse or extract pieces
- Ignore empty/partial deep-link invocations instead of forwarding them
- Verify the OAuth redirect URI matches the registered deep-link scheme
When it happens
Trigger: Calling completeOpenAiCodexOAuth('') or completeOpenAiCodexOAuth(' ') — e.g. a deep-link handler that fires on the bare scheme openhuman://oauth without the path/query, or a race where the handler runs before the URL is captured.
Common situations: Deep-link registration handling only part of the URL; the callback arriving with query params stripped by a browser/launcher; manual testing that calls the completer without a real redirect; string parsing that extracts the wrong segment and yields empty.
Related errors
- OPENAI_CODEX_OAUTH_MISSING_AUTH_URL
- provider is required
- Finish choosing how OpenHuman runs (tap Continue on the setu
- OpenHuman could not reach its remote (cloud) runtime. Check
- agentTeamApi: ${label} must be a positive integer
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/5497320ffad62ef7.
Report an issue: GitHub.