{"record":{"id":"ceca26da1d25a409","repo":"odysseus-dev/odysseus","slug":"invalid-include-pattern","errorCode":null,"errorMessage":"Invalid include pattern","messagePattern":"Invalid include pattern","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/cookbook_helpers.py","lineNumber":83,"sourceCode":"def _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\")\n    return v\n\n\ndef load_stored_hf_token(*, state_path: Path | str | None = None) -> str:\n    \"\"\"Return the decrypted HF token from cookbook_state.json, else env fallback.\"\"\"\n    path = Path(state_path) if state_path else Path(os.environ.get(\"DATA_DIR\", \"data\")) / \"cookbook_state.json\"\n    token = \"\"\n    if path.exists():\n        try:\n            state = json.loads(path.read_text(encoding=\"utf-8\"))","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/cookbook_helpers.py#L65-L101","documentation":"HTTP 400 from _validate_include() in routes/cookbook_helpers.py when a non-empty include pattern fails _INCLUDE_RE. Include patterns are constrained file-glob fragments used as download filters; the regex limits allowed characters/shape, so arbitrary glob syntax or shell text is rejected. Empty string and None are allowed and normalize to None.","triggerScenarios":"Passing include=\"**/*.{safetensors,json}\", include=\"src/**; rm -rf\", include=\"../../../etc/passwd\", or any pattern containing characters outside _INCLUDE_RE's allowlist.","commonSituations":"Users copying rsync/find glob syntax (**, braces, negation !) that the allowlist does not support; attempting traversal paths; embedding spaces or shell operators that could break the underlying download-filter command.","solutions":["Simplify the pattern to a plain glob like *.safetensors or *.json","Read _INCLUDE_RE at the top of routes/cookbook_helpers.py and conform to its allowed characters","Omit include entirely when you want all files"],"exampleFix":"// before\n{\"include\": \"**/*.{safetensors,json}\"}\n// after\n{\"include\": \"*.safetensors\"}","handlingStrategy":"validation","validationCode":"import re\nINCLUDE_RE = re.compile(r\"^[A-Za-z0-9*._/\\[\\]-]+$\")  # mirror the server's _INCLUDE_RE; read the real one from cookbook_helpers.py\n\ndef safe_include(v):\n    if v is None or v == \"\":\n        return None\n    v = v.strip()\n    if not INCLUDE_RE.match(v):\n        raise ValueError(\"include pattern uses unsupported characters\")\n    return v","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Stick to simple globs (*.safetensors, *.json)","Omit include when you want everything","Do not port rsync/find glob syntax (**, braces, !) into this field"],"tags":["validation","glob-pattern","http-400","download"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}