unslothai/unsloth · warning · HTTPException

command must not be empty

Error message

command must not be empty

What it means

400 raised in _validate_url's stdio branch when the value is recognized as a local command (stdio enabled, non-http) and parse_stdio_command succeeds, but the parsed argv is empty or its first token is blank. This is the command-mode equivalent of an empty URL — there is no executable to run.

Source

Thrown at studio/backend/routes/mcp_servers.py:80

def _validate_url(url: str) -> str:
    trimmed = (url or "").strip()
    if not trimmed:
        raise HTTPException(status_code = 400, detail = "url must not be empty")
    # When stdio is enabled, a non-HTTP value is a local command (reuses this
    # field so stdio servers ride existing CRUD/storage).
    if stdio_mcp_enabled() and is_stdio(trimmed):
        try:
            parts = parse_stdio_command(trimmed)
        except ValueError as exc:
            raise log_and_http_error(
                exc,
                400,
                "Invalid command. Check quoting and try again.",
                event = "mcp_servers.invalid_command",
                log = logger,
            )
        if not parts or not parts[0].strip():
            raise HTTPException(status_code = 400, detail = "command must not be empty")
        if "://" in parts[0]:
            # A URL-scheme first token is a mistyped URL, not a command. Reject
            # cleanly instead of exec-ing it (mirrors the frontend check).
            raise HTTPException(
                status_code = 400,
                detail = "Enter an http(s):// URL, or a local command whose "
                "first token is an executable (not a URL).",
            )
        return trimmed
    parsed = urlparse(trimmed)
    if parsed.scheme not in ("http", "https"):
        if _looks_like_command(trimmed):
            detail = (
                "Local commands aren't enabled on this server. To allow them, "
                "set UNSLOTH_STUDIO_ALLOW_STDIO_MCP=1 and restart Unsloth, or use "
                "an http:// or https:// URL instead."
            )
        else:

View on GitHub (pinned to 203007d190)

Solutions

  1. Ensure the first whitespace-separated token is a real executable, e.g. 'npx -y @modelcontextprotocol/server-filesystem /path'.
  2. Log/echo the exact string being sent before the request when building commands dynamically.
  3. Add a client-side check that the trimmed command has at least one non-empty token.

Example fix

# before
client.post('/api/mcp-servers/', json={'display_name': 'x', 'url': '   '})
# with stdio enabled -> 400 'command must not be empty'

# after
cmd = ' '.join(part for part in [exe, *args] if part)
assert cmd.split()[0], 'command executable missing'
client.post('/api/mcp-servers/', json={'display_name': 'x', 'url': cmd})
Defensive patterns

Strategy: validation

Validate before calling

const parts = command.trim().split(/\s+/);
if (!parts[0] || !parts[0].trim()) throw new Error('Command needs an executable as its first token');

Type guard

function hasExecutable(cmd) { const t = (cmd ?? '').trim(); return t.length > 0 && t.split(/\s+/)[0].length > 0; }

Prevention

When it happens

Trigger: Creating/updating an MCP server with url values like ' "" ' or a quoted-empty command that shell-parses to zero tokens while stdio MCP is enabled (UNSLOTH_STUDIO_ALLOW_STDIO_MCP=1 or loopback default).

Common situations: Programmatically building a command string from variables that are all empty, or copy-pasting a placeholder like "<command>" that reduces to nothing after quote parsing.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/75c854a0f30a7070. Report an issue: GitHub.