odysseus-dev/odysseus · error · HTTPException
Invalid characters in cmd
Error message
Invalid characters in cmd
What it means
HTTP 400 from the serve-cmd validator in routes/cookbook_helpers.py (~line 764). After collapsing backslash-newline continuations into spaces, the command is scanned for characters that are never legitimate in this field: backticks and raw CR/LF newlines. Their presence suggests command substitution or multi-line shell input that the leading-token allowlist cannot reason about safely.
Source
Thrown at routes/cookbook_helpers.py:764
`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
pre-fix world) could pass arbitrary shell payloads.
Leading env-var assignments (e.g. `CUDA_VISIBLE_DEVICES=0 python3 ...`)
are stripped before checking the binary — several of our cmd builders
prepend them, and they shouldn't trip the allowlist.
"""
if v is None or v == "":
return None
# Collapse backslash-newline line continuations into single spaces. Serve
# commands (vLLM especially) are routinely pasted multi-line with trailing
# `\` — that's a safe shell/shlex continuation, so the command stays ONE
# logical invocation and the leading-token allowlist below still governs.
v = re.sub(r"\\[ \t]*\r?\n[ \t]*", " ", v).strip()
# Backticks and raw newlines are never legitimate here.
if any(c in v for c in ("`", "\n", "\r")):
raise HTTPException(400, "Invalid characters in cmd")
# Known GGUF launcher prelude → validate the serve invocation(s) it guards.
m = _GGUF_PRELUDE_RE.match(v)
if m:
rest = v[m.end():]
# rest is `[ENV=…] python3 -m llama_cpp.server … || [ENV=…] llama-server …`
for part in rest.split("||"):
_check_serve_binary(part.strip())
return v
# Otherwise: a single invocation — no shell metacharacters allowed. Replace
# only the exact command substitutions emitted by the Cookbook UI:
# $(printf %s 'safe-path') and the mmproj lookup
# $(find <path> -iname 'mmproj*.gguf' 2>/dev/null | sort | head -1).
def _replace_safe_subshell(match: re.Match[str]) -> str:
subshell = match.group(0)
return "/placeholder/safe/path" if _is_safe_serve_subshell(subshell) else subshell
View on GitHub (pinned to f9235ebbf1)
Solutions
- Replace backtick substitutions with literal values before submitting
- Keep the command on one logical line; use trailing backslash only for line continuations
- Strip CR characters client-side when submitting from Windows (normalize CRLF to spaces)
- Compute any dynamic value client-side and inline the result into cmd
Example fix
# before cmd = "vllm serve `cat /tmp/model.txt` --port 8000" # after cmd = "vllm serve mistralai/Mistral-7B --port 8000"
Defensive patterns
Strategy: validation
Validate before calling
import re
def clean_serve_cmd(cmd: str) -> str:
cmd = re.sub(r"\\[ \t]*\r?\n[ \t]*", " ", cmd).strip()
if any(c in cmd for c in ("`", "\n", "\r")):
raise ValueError("cmd contains backtick or raw newline")
return cmd Prevention
- Expand all substitutions client-side; submit literal values
- Normalize CRLF before submitting from Windows
- Never paste heredocs or multi-line shell into the cmd field
When it happens
Trigger: cmd containing a backtick substitution such as "vllm serve `cat /tmp/model.txt` --port 8000"; a cmd pasted with embedded newlines that are not backslash continuations; a CRLF paste leaving a raw carriage return.
Common situations: Windows users pasting CRLF commands so a stray CR survives; users writing backtick-style substitution instead of $(); copying a multi-line shell heredoc into the cmd field.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- repo_id is required
- Invalid repo_id — must be <org>/<name>, an Ollama name:tag,
- Invalid local_dir — must be an absolute or ~ path with no sh
- Invalid cmd — could not parse
- Invalid pip package name
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/170868286e63d000.
Report an issue: GitHub.