unslothai/unsloth · warning · CodexAuthError
The callback URL did not contain an authorization code.
Error message
The callback URL did not contain an authorization code.
What it means
Raised as CodexAuthError by complete_browser_flow as the final check before token exchange: the callback URL is structurally valid and the state matches, but the 'code' query parameter is absent or empty. OpenAI always appends code on a successful consent; an absent code usually means the redirect carried an error (e.g. error=access_denied) or the URL was truncated right where the code begins.
Source
Thrown at studio/backend/core/inference/openai_codex_auth.py:625
flow = get_flow(provider_id, flow_id)
if flow.method != "browser" or flow.status != "pending" or flow.consumed:
raise CodexAuthError("Authorization flow is no longer active.")
parsed = urlparse(callback_url)
expected = urlparse(flow.redirect_uri)
if (
parsed.scheme != expected.scheme
or parsed.hostname != expected.hostname
or parsed.port != expected.port
or parsed.path != expected.path
or parsed.fragment
):
raise CodexAuthError("Paste the complete localhost ChatGPT callback URL.")
query = parse_qs(parsed.query)
if not secrets.compare_digest(query.get("state", [""])[0], flow.state):
raise CodexAuthError("Authorization state did not match.")
code = query.get("code", [""])[0]
if not code:
raise CodexAuthError("The callback URL did not contain an authorization code.")
await _exchange_code(flow, code)
return flow
async def cancel_flow(flow_id: str) -> None:
flow = _flows.pop(flow_id, None)
if not flow:
return
flow.status = "cancelled"
if flow.task:
flow.task.cancel()
if flow.cleanup_task and flow.cleanup_task is not asyncio.current_task():
flow.cleanup_task.cancel()
if flow.server:
flow.server.close()
await flow.server.wait_closed()
View on GitHub (pinned to 203007d190)
Solutions
- If consent was denied, restart the flow and approve the ChatGPT permission prompt.
- Re-copy the complete callback URL — the code parameter is long and often the truncated part.
- Paste into a plain text editor first to verify the full query string survived.
- Check the URL for an error= parameter; its value tells you why OpenAI omitted the code.
Example fix
// before
await codex_auth.complete_browser_flow(provider_id, flow_id, url_without_code)
// after
from urllib.parse import urlparse, parse_qs
q = parse_qs(urlparse(callback_url).query)
if not q.get("code"):
raise ValueError(f"callback missing code; error={q.get('error')}")
await codex_auth.complete_browser_flow(provider_id, flow_id, callback_url) Defensive patterns
Strategy: validation
Validate before calling
q = parse_qs(urlparse(callback_url).query)
if not q.get("code", [""])[0]:
err = q.get("error", ["unknown"])[0]
reject(f"no authorization code (error={err}); user likely denied consent") Type guard
def callback_has_code(callback_url: str) -> bool:
from urllib.parse import urlparse, parse_qs
return bool(parse_qs(urlparse(callback_url).query).get("code", [""])[0]) Try / catch
try:
flow = await codex_auth.complete_browser_flow(provider_id, flow_id, pasted)
except codex_auth.CodexAuthError as exc:
if "did not contain an authorization code" in str(exc):
ask_user_to_recopy_or_reapprove() # truncated paste or denied consent
else:
raise Prevention
- Check for a code= parameter client-side and surface the error= reason when present.
- Copy the entire URL; the code is the longest parameter and truncates first.
- Handle access_denied with a friendly 'permission denied' message.
- Paste via plain text to avoid smart-copy mangling.
When it happens
Trigger: User denied the ChatGPT consent so the redirect contains error=access_denied with no code; the pasted URL was cut off before &code=...; query parameters reordered/dropped by a URL handler; consent timed out server-side redirecting with an error.
Common situations: Consent denial is the most common case; over-eager copy tools truncating long URLs at line breaks; messaging apps splitting the URL; the user copying while the page was mid-redirect.
Related errors
- Authorization callback was invalid or already used.
- Authorization flow is no longer active.
- Paste the complete localhost ChatGPT callback URL.
- Bad candidate spec fragment '{part}' (expected key=value)
- ChatGPT credential update is busy. Please retry.
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/f23f890b8a9dae27.
Report an issue: GitHub.