odysseus-dev/odysseus · warning · HTTPException

Invalid ssh_port

Error message

Invalid ssh_port

What it means

HTTPException(400) from validate_ssh_port: the value does not fullmatch ^\d{1,5}$ — it contains non-digit characters (letters, whitespace, a 'tcp://' prefix) or is empty after being passed as a non-string. This is the format-level guard before the numeric range check.

Source

Thrown at routes/_validators.py:27

_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

  1. Send the port as a plain digit string or integer, e.g. '22' or 2222
  2. Trim whitespace client-side before submitting
  3. Use the same field name the endpoint expects (ssh_port), not an alias

Example fix

# before
ssh_port="22/tcp"
# after
ssh_port="22"
Defensive patterns

Strategy: validation

Validate before calling

ssh_port = str(ssh_port or '').strip()
if not ssh_port.isdigit():
    raise ValueError('ssh_port must be digits only')

Type guard

def is_digits(v) -> bool:
    s = str(v or '').strip()
    return bool(s) and s.isdigit()

Try / catch

try:
    resp = client.post('/api/remote', data={'ssh_port': p})
except HTTPError as e:
    if e.response.status_code == 400 and 'ssh_port' in e.response.text:
        p = re.sub(r'\D', '', str(p)); retry()
    raise

Prevention

When it happens

Trigger: Submitting ssh_port='22 ' (trailing space), 'port 22', '22/tcp', or a float like 22.0 in the request payload.

Common situations: Copy-pasting port from documentation prose; UI not trimming whitespace; serializing the field as a number with a decimal point on the client.

Related errors


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