odysseus-dev/odysseus · error · HTTPException

Invalid include pattern

Error message

Invalid include pattern

What it means

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.

Source

Thrown at routes/cookbook_helpers.py:83

def _validate_repo_id(v: str | None) -> str:
    if not v or not _REPO_ID_RE.match(v):
        raise HTTPException(400, "Invalid repo_id — must be <org>/<name> using [A-Za-z0-9._-]")
    return v


def _validate_serve_model_id(v: str | None) -> str:
    if not v:
        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"))

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Simplify the pattern to a plain glob like *.safetensors or *.json
  2. Read _INCLUDE_RE at the top of routes/cookbook_helpers.py and conform to its allowed characters
  3. Omit include entirely when you want all files

Example fix

// before
{"include": "**/*.{safetensors,json}"}
// after
{"include": "*.safetensors"}
Defensive patterns

Strategy: validation

Validate before calling

import re
INCLUDE_RE = re.compile(r"^[A-Za-z0-9*._/\[\]-]+$")  # mirror the server's _INCLUDE_RE; read the real one from cookbook_helpers.py

def safe_include(v):
    if v is None or v == "":
        return None
    v = v.strip()
    if not INCLUDE_RE.match(v):
        raise ValueError("include pattern uses unsupported characters")
    return v

Prevention

When it happens

Trigger: Passing include="**/*.{safetensors,json}", include="src/**; rm -rf", include="../../../etc/passwd", or any pattern containing characters outside _INCLUDE_RE's allowlist.

Common situations: 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.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/ceca26da1d25a409. Report an issue: GitHub.