odysseus-dev/odysseus · error · HTTPException

cmd binary '{base or '(empty)'}' is not allowed. Must start

Error message

cmd binary '{base or '(empty)'}' is not allowed. Must start with one of: {', '.join(sorted(_SERVE_CMD_ALLOWLIST))}

What it means

HTTP 400 from _check_serve_binary() in routes/cookbook_helpers.py: the command's first meaningful token (after skipping leading VAR=value assignments like CUDA_VISIBLE_DEVICES=0) has a basename that is not in _SERVE_CMD_ALLOWLIST. Only allowlisted server binaries may be launched; everything else — shells, curl, arbitrary executables — is refused.

Source

Thrown at routes/cookbook_helpers.py:730

        return f"{match.group('flag')}{match.group('sep')}{quote}{mapped}{quote}"

    return _LLAMA_CPP_PYTHON_TYPE_FLAG_RE.sub(repl, cmd)


def _check_serve_binary(seg: str) -> None:
    """Validate that a single command segment starts with an allowlisted binary
    (after skipping leading env-var assignments like `CUDA_VISIBLE_DEVICES=0`)."""
    try:
        tokens = shlex.split(seg) if seg.strip() else []
    except ValueError:
        raise HTTPException(400, "Invalid cmd — could not parse")
    if not tokens:
        return
    env_re = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*=")
    first = next((t for t in tokens if not env_re.match(t)), "")
    base = os.path.basename(first)
    if base not in _SERVE_CMD_ALLOWLIST:
        raise HTTPException(
            400,
            f"cmd binary '{base or '(empty)'}' is not allowed. Must start with one of: "
            f"{', '.join(sorted(_SERVE_CMD_ALLOWLIST))}",
        )


def _is_safe_serve_subshell(subshell: str) -> bool:
    return bool(
        _SAFE_PRINTF_SUBSHELL_RE.fullmatch(subshell)
        or _SAFE_FIND_MMPROJ_SUBSHELL_RE.fullmatch(subshell)
    )


def _validate_serve_cmd(v: str | None) -> str | None:
    """Reject serve commands that aren't in the allowlist or contain shell metachars.

    `req.cmd` is dropped verbatim into a bash/PowerShell wrapper script and
    executed in a tmux session. Without this gate, an admin (or anyone in the

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Start the command directly with an allowlisted binary — the error message lists the full sorted allowlist (e.g. vllm, llama-server, python3)
  2. Drop bash -c / sh -c / ./script.sh wrappers and invoke the server binary itself
  3. If a new binary is legitimately needed, add it to _SERVE_CMD_ALLOWLIST in routes/cookbook_helpers.py and review the security implications
  4. Put environment setup in env_prefix or leading VAR=value assignments, not in a wrapper command

Example fix

# before
cmd = "bash -c 'vllm serve mistralai/Mistral-7B --port 8000'"
# after
cmd = "vllm serve mistralai/Mistral-7B --port 8000"
Defensive patterns

Strategy: validation

Validate before calling

import os, re, shlex
# Mirror the server list; keep in sync with _SERVE_CMD_ALLOWLIST in cookbook_helpers.py:
_SERVE_CMD_ALLOWLIST = {"vllm", "llama-server", "python3"}

def first_binary(cmd: str) -> str:
    tokens = shlex.split(cmd)
    env_re = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*=")
    first = next((t for t in tokens if not env_re.match(t)), "")
    return os.path.basename(first)

if first_binary(cmd) not in _SERVE_CMD_ALLOWLIST:
    raise ValueError(f"binary {first_binary(cmd)!r} not allowlisted")

Prevention

When it happens

Trigger: cmd="bash -c 'vllm serve ...'", cmd="./start.sh", cmd="python -m myserver ..." (python vs python3), or a segment containing only env assignments, yielding '(empty)'.

Common situations: Using a wrapper script or shell to start the model server; using 'python' instead of 'python3'; a new or renamed inference binary that has not been added to _SERVE_CMD_ALLOWLIST yet; trying to run arbitrary commands through the serve endpoint.

Related errors


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