BerriAI/litellm · error · UpError
Login did not produce a usable token; cannot start `lite up`
Error message
Login did not produce a usable token; cannot start `lite up`.
What it means
Raised by `lite up` after it invoked the interactive login flow (ctx.invoke(login)) but the reloaded token still fails the usability check: missing, wrong base_url, or stale per is_cli_token_fresh. It means the login flow returned without raising yet did not persist a token usable for this proxy — e.g. the browser SSO was never completed, or the token that landed in ~/.litellm/token.json belongs to a different server. `up` aborts rather than patch Claude Code settings with an apiKeyHelper that would fail on every request.
Source
Thrown at litellm/proxy/client/cli/commands/up.py:175
def _ensure_fresh_login(ctx: click.Context) -> None:
base_url: Final = ctx.obj["base_url"].rstrip("/")
token_data = load_token()
if token_data and token_data.get("base_url") == base_url and is_cli_token_fresh(token_data):
return
if not sys.stdin.isatty():
raise UpError(
"No fresh LiteLLM login found for this proxy. Run `lite login` first (apiKeyHelper "
"reads this token on every Claude Code request)."
)
click.echo("No fresh LiteLLM login found for this proxy; starting login...")
ctx.invoke(login)
token_data = load_token()
if not token_data or token_data.get("base_url") != base_url or not is_cli_token_fresh(token_data):
raise UpError("Login did not produce a usable token; cannot start `lite up`.")
def _restore_and_report() -> None:
record: Final = restore_claude_settings()
if record is None:
click.echo("Nothing to restore.")
return
if record.existed:
click.echo(f"Restored {CLAUDE_SETTINGS_PATH} to its original contents.")
else:
click.echo(f"Removed {CLAUDE_SETTINGS_PATH} (it did not exist before `lite up`).")
@click.command(name="up")
@click.pass_context
def up(ctx: click.Context) -> None:
"""Route every Claude Code session through your LiteLLM proxy until stopped.
View on GitHub (pinned to 77b7c6c40c)
Solutions
- Run `lite login` standalone in the same terminal against the same proxy, complete the browser flow, and confirm `lite auth print-token --base-url <url>` prints a token
- Verify ~/.litellm/token.json afterwards: `base_url` must exactly match the proxy `up` uses and `timestamp` must be fresh
- If no browser can open on this machine, run `lite login` where one can and copy ~/.litellm/token.json (mode 0600) over
- Check for a concurrent LiteLLM login/logout (CI job, another terminal) rewriting the token file
Example fix
# before lite up # "No fresh LiteLLM login found; starting login..." # UpError: Login did not produce a usable token; cannot start `lite up`. # after lite login --base-url https://proxy.internal # complete SSO in the browser lite auth print-token --base-url https://proxy.internal # sanity check lite up
Defensive patterns
Strategy: retry
Validate before calling
import subprocess
def ensure_login() -> None:
if subprocess.call(["lite", "auth", "print-token", "--base-url", BASE_URL]) != 0:
subprocess.check_call(["lite", "login", "--base-url", BASE_URL]) # interactive repair
subprocess.check_call(["lite", "auth", "print-token", "--base-url", BASE_URL]) # verify Try / catch
import subprocess, sys
for attempt in (1, 2):
rc = subprocess.call(["lite", "up"])
if rc == 0:
break
if attempt == 1:
subprocess.call(["lite", "login"]) # one interactive repair, then one retry
else:
sys.exit("`lite up` failed twice — inspect ~/.litellm/token.json manually") Prevention
- Confirm `lite auth print-token --base-url <proxy>` succeeds before starting `lite up`
- Ensure a browser can open on the machine running login (or run login elsewhere and copy token.json with mode 0600)
- Avoid concurrent `lite login`/`lite logout` in other terminals while `up` is starting
When it happens
Trigger: Canceling or never opening the browser during `lite login`'s device/SSO flow; logging in against a different --base-url than the one `up` targets; the login poll finishing without writing token.json; a concurrent process (logout, second login) overwriting the token file between login and the re-check.
Common situations: Headless/SSH session with no browser so SSO never completed; clock skew on the machine making a just-issued token appear stale; proxy behind a URL rewrite so the stored base_url differs from the CLI's; two terminals running LiteLLM logins against different proxies clobbering one token.json.
Related errors
- You must be a LiteLLM Enterprise user to use this feature. I
- custom_ui_sso_sign_in_handler is not configured. Please set
- User role is required for CLI JWT login
- Could not find `lite` on your PATH. Claude Code's apiKeyHelp
- No fresh LiteLLM login found for this proxy. Run `lite login
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/8ebabcf9a06083d4.
Report an issue: GitHub.