odysseus-dev/odysseus · warning · HTTPException
Invalid remote_host — must be host or user@host, no SSH opti
Error message
Invalid remote_host — must be host or user@host, no SSH option syntax
What it means
A FastAPI HTTPException(400) from validate_remote_host: the remote_host value failed the strict regex that permits only 'host' or 'user@host' forms (letters, digits, dots, underscores, hyphens). Anything carrying SSH option syntax — '-p 22', '-i key', 'ssh://...' — is rejected to prevent option injection into downstream ssh commands.
Source
Thrown at routes/_validators.py:16
import re
from fastapi import HTTPException
_REMOTE_HOST_RE = re.compile(
r"^(?:[A-Za-z0-9][A-Za-z0-9._-]*@)?[A-Za-z0-9][A-Za-z0-9._-]*$"
)
_SSH_PORT_RE = re.compile(r"^\d{1,5}$")
def validate_remote_host(v: str | None) -> str | None:
if v is None or v == "":
return None
if not _REMOTE_HOST_RE.match(v):
raise HTTPException(
400,
"Invalid remote_host — must be host or user@host, no SSH option syntax",
)
return v
def validate_ssh_port(v: str | None) -> str | None:
if v is None or v == "":
return None
if not _SSH_PORT_RE.fullmatch(str(v)):
raise HTTPException(400, "Invalid ssh_port")
port = int(v)
if port < 1 or port > 65535:
raise HTTPException(400, "Invalid ssh_port")
return str(port)
View on GitHub (pinned to f9235ebbf1)
Solutions
- Send only 'user@host' or 'host'; move the port into the separate ssh_port field
- Remove ssh:// scheme prefixes and option flags
- For IPv6, file a feature request / use a hostname, since the regex rejects colons and brackets
Example fix
# before remote_host="user@host -p 2222" # after remote_host="user@host", ssh_port=2222
Defensive patterns
Strategy: validation
Validate before calling
import re
REMOTE = re.compile(r'^(?:[A-Za-z0-9][A-Za-z0-9._-]*@)?[A-Za-z0-9][A-Za-z0-9._-]*$')
if not REMOTE.match(remote_host or ''):
remote_host = remote_host.split()[-1].lstrip('ssh://') # or reject client-side Type guard
def is_valid_remote_host(v: str | None) -> bool:
return v is None or bool(re.match(r'^(?:[A-Za-z0-9][A-Za-z0-9._-]*@)?[A-Za-z0-9][A-Za-z0-9._-]*$', v)) Try / catch
try:
resp = client.post('/api/remote', data={'remote_host': h})
except HTTPError as e:
if e.response.status_code == 400 and 'remote_host' in e.response.text:
h = extract_bare_host(h); retry()
raise Prevention
- Split host and port into separate fields in the UI
- Strip ssh:// and flags before submitting
- Add client-side regex mirroring the server rule
When it happens
Trigger: POSTing a remote-host form/API payload with remote_host like 'ssh -p 2222 host', 'user@host -i ~/.ssh/id_ed25519', 'ssh://user@host:22', or an IPv6 literal with brackets/colons.
Common situations: Users pasting a full ssh command line into a host field; URLs instead of bare hostnames; bracketed IPv6 addresses which the character class does not allow.
Related errors
- Invalid ssh_port
- Unknown wipe kind: {kind!r}
- ssh_port requires host
- No files uploaded
- HTTP ${res.status}${body ? ': ' + body.slice(0, 160) : ''}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/a23bf85a9596cad6.
Report an issue: GitHub.