odysseus-dev/odysseus · error · HTTPException
Invalid token characters
Error message
Invalid token characters
What it means
HTTP 400 from _validate_token() in routes/cookbook_helpers.py when a non-empty token fails _TOKEN_RE. Hugging Face tokens are restricted to a conservative character set (alphanumerics and typical token punctuation); spaces, quotes, shell metacharacters, or stray characters cause rejection. Empty/None is allowed (returns None).
Source
Thrown at routes/cookbook_helpers.py:91
raise HTTPException(400, "repo_id is required")
if _REPO_ID_RE.match(v) or _LOCAL_MODEL_ID_RE.match(v) or _OLLAMA_MODEL_ID_RE.match(v):
return v
raise HTTPException(400, "Invalid repo_id — must be <org>/<name>, an Ollama name:tag, or a cached local model id")
def _validate_include(v: str | None) -> str | None:
if v is None or v == "":
return None
if not _INCLUDE_RE.match(v):
raise HTTPException(400, "Invalid include pattern")
return v
def _validate_token(v: str | None) -> str | None:
if v is None or v == "":
return None
if not _TOKEN_RE.match(v):
raise HTTPException(400, "Invalid token characters")
return v
def load_stored_hf_token(*, state_path: Path | str | None = None) -> str:
"""Return the decrypted HF token from cookbook_state.json, else env fallback."""
path = Path(state_path) if state_path else Path(os.environ.get("DATA_DIR", "data")) / "cookbook_state.json"
token = ""
if path.exists():
try:
state = json.loads(path.read_text(encoding="utf-8"))
env = state.get("env") if isinstance(state, dict) else {}
if isinstance(env, dict) and env.get("hfToken"):
from src.secret_storage import decrypt
token = decrypt(env.get("hfToken") or "")
except Exception:
token = ""
if not token:
token = (os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN") or "").strip()View on GitHub (pinned to f9235ebbf1)
Solutions
- Send only the raw token string, no quotes or whitespace — trim it client-side first
- Re-copy the token from your HF settings page in case it was truncated or mangled
- Check _TOKEN_RE in routes/cookbook_helpers.py for the exact allowed characters
Example fix
// before
token = `"${process.env.HF_TOKEN}"` // sends wrapping quotes
// after
token = process.env.HF_TOKEN.trim() Defensive patterns
Strategy: validation
Validate before calling
import re
TOKEN_RE = re.compile(r"^[A-Za-z0-9_.\-]+$") # conservative mirror of _TOKEN_RE
def clean_token(v):
if v is None or v == "":
return None
v = v.strip().strip('"').strip("'")
if not TOKEN_RE.match(v):
raise ValueError("token contains invalid characters after trimming")
return v Prevention
- Trim whitespace and strip wrapping quotes before sending
- Never send the whole `huggingface-cli login` line — only the token
- Read tokens from a secret store, not from pasted shell history
When it happens
Trigger: Sending token="hf_abc123 " (trailing space), a token with a newline from clipboard paste, a quoted token (\"hf_...\"), or a token containing $, ;, |, or backticks.
Common situations: Copy-pasting the token with surrounding whitespace or quotes; pasting an entire `huggingface-cli login` command instead of just the token; a truncated token that no longer matches the expected charset.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid repo_id — must be <org>/<name> using [A-Za-z0-9._-]
- await res.text()
- {key} must be an integer
- Invalid JSON
- Expected a JSON object
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/02eec35e77e703f2.
Report an issue: GitHub.