{"record":{"id":"2f7f31afc6fcf1d2","repo":"odysseus-dev/odysseus","slug":"repo-id-is-required","errorCode":null,"errorMessage":"repo_id is required","messagePattern":"repo_id is required","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/cookbook_helpers.py","lineNumber":73,"sourceCode":"\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\n\ndef _validate_token(v: str | None) -> str | None:\n    if v is None or v == \"\":\n        return None\n    if not _TOKEN_RE.match(v):\n        raise HTTPException(400, \"Invalid token characters\")","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/cookbook_helpers.py#L55-L91","documentation":"HTTP 400 from _validate_serve_model_id() in routes/cookbook_helpers.py when the model identifier is None or an empty string. Serve endpoints require some identifier — HF repo id, Ollama name:tag, or cached local model id — before format-specific validation runs.","triggerScenarios":"POST to a serve endpoint with repo_id omitted from the JSON body, set to null, or set to \"\".","commonSituations":"Frontend form submitted before the model field was filled; client code that conditionally omits repo_id when the user picked a custom-command mode; a refactor that renamed the field (model vs repo_id) so the key never arrives.","solutions":["Include a non-empty repo_id in the request body","Check the exact field name the request model expects (repo_id, not model or model_id)","If serving a raw command with no model, use the endpoint variant that does not require repo_id, or pass a valid model id"],"exampleFix":"// before\n{\"cmd\": \"vllm serve ...\"}  // repo_id missing\n// after\n{\"repo_id\": \"meta-llama/Meta-Llama-3-8B\", \"cmd\": \"vllm serve ...\"}","handlingStrategy":"type-guard","validationCode":"def has_serve_model_id(payload: dict) -> bool:\n    rid = payload.get(\"repo_id\")\n    return isinstance(rid, str) and rid.strip() != \"\"","typeGuard":"function isServeRequest(p: unknown): p is ServeRequest {\n  return (\n    typeof p === \"object\" && p !== null &&\n    typeof (p as any).repo_id === \"string\" &&\n    (p as any).repo_id.trim() !== \"\"\n  );\n}","tryCatchPattern":null,"preventionTips":["Disable the submit button until repo_id is non-empty","Use a required field client-side so the key is never omitted","Log the outgoing payload shape when a 400 mentions repo_id to catch renamed keys"],"tags":["validation","serve","required-field","http-400"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}