{"record":{"id":"43d2021dd4d418b9","repo":"odysseus-dev/odysseus","slug":"invalid-repo-id-must-be-org-name-using-a-za","errorCode":null,"errorMessage":"Invalid repo_id — must be <org>/<name> using [A-Za-z0-9._-]","messagePattern":"Invalid repo_id — must be <org>/<name> using \\[A-Za-z0-9\\._-\\]","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/cookbook_helpers.py","lineNumber":67,"sourceCode":"# shell-safe: none of ``; & | ` $ '' \"\" () {}`` newlines etc. are in ``[\\w. -]``,\n# so injection vectors remain rejected. A leading ~ is expanded to $HOME at\n# command-build time. (Drive letters stay ASCII: ``[A-Za-z]:``.)\n_LOCAL_DIR_RE = re.compile(r\"^~?(?:/[\\w. -]*)+$|^~$\")\n_WINDOWS_LOCAL_DIR_RE = re.compile(r\"^[A-Za-z]:[\\\\/](?:[\\w. -]+(?:[\\\\/][\\w. -]+)*[\\\\/]?)?$\")\n_WINDOWS_DRIVE_PATH_RE = re.compile(r\"^[A-Za-z]:[\\\\/]\")\n\n\ndef _git_bash_path(path: str) -> str:\n    m = re.match(r\"^([A-Za-z]):[\\\\/](.*)$\", path)\n    if not m:\n        return path\n    drive, rest = m.groups()\n    return f\"/{drive.lower()}/{rest.replace(chr(92), '/')}\"\n\n\ndef _validate_repo_id(v: str | None) -> str:\n    if not v or not _REPO_ID_RE.match(v):\n        raise HTTPException(400, \"Invalid repo_id — must be <org>/<name> using [A-Za-z0-9._-]\")\n    return v\n\n\ndef _validate_serve_model_id(v: str | None) -> str:\n    if not v:\n        raise HTTPException(400, \"repo_id is required\")\n    if _REPO_ID_RE.match(v) or _LOCAL_MODEL_ID_RE.match(v) or _OLLAMA_MODEL_ID_RE.match(v):\n        return v\n    raise HTTPException(400, \"Invalid repo_id — must be <org>/<name>, an Ollama name:tag, or a cached local model id\")\n\n\ndef _validate_include(v: str | None) -> str | None:\n    if v is None or v == \"\":\n        return None\n    if not _INCLUDE_RE.match(v):\n        raise HTTPException(400, \"Invalid include pattern\")\n    return v\n","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/cookbook_helpers.py#L49-L85","documentation":"HTTP 400 from _validate_repo_id() in routes/cookbook_helpers.py. The value must fully match _REPO_ID_RE, i.e. a Hugging Face style <org>/<name> built only from [A-Za-z0-9._-]. Empty, None, extra slashes, spaces, unicode, or a missing org/name split all fail.","triggerScenarios":"Calling a cookbook endpoint that validates repo_id with values like \"model\" (no slash), \"org/a/b\" (two slashes), \"org/name extra\" (space), \"\" or null, or an Ollama id (\"llama3:8b\") sent to an endpoint that only accepts HF repo ids.","commonSituations":"Passing a bare model name without the org; copying a full HF URL (https://huggingface.co/org/name) instead of the id; trailing whitespace or invisible unicode from copy-paste.","solutions":["Send the exact Hugging Face repo id: <org>/<name>, e.g. mistralai/Mistral-7B-Instruct-v0.2","Strip whitespace and drop the https://huggingface.co/ prefix before sending","If you meant an Ollama or local cached model, use an endpoint whose validator accepts those (_validate_serve_model_id)","Check _REPO_ID_RE at the top of routes/cookbook_helpers.py for the authoritative pattern"],"exampleFix":"// before\n{\"repo_id\": \"https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.2\"}\n// after\n{\"repo_id\": \"mistralai/Mistral-7B-Instruct-v0.2\"}","handlingStrategy":"validation","validationCode":"import re\nREPO_ID_RE = re.compile(r\"^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$\")\n\ndef is_valid_repo_id(v):\n    return bool(v) and bool(REPO_ID_RE.match(v))\n\nassert is_valid_repo_id(\"mistralai/Mistral-7B-Instruct-v0.2\")","typeGuard":null,"tryCatchPattern":"try:\n    r = client.post(\"/cookbook/download\", json={\"repo_id\": rid})\nexcept HTTPException as e:\n    if e.status_code == 400 and \"repo_id\" in e.detail:\n        rid = prompt_user_for_exact_hf_id()\n    else:\n        raise","preventionTips":["Send the bare HF id <org>/<name>, never the full URL","Strip whitespace and URL prefixes client-side","Reserve Ollama/local ids for endpoints that use _validate_serve_model_id"],"tags":["validation","huggingface","repo-id","http-400"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}