{"record":{"id":"75c854a0f30a7070","repo":"unslothai/unsloth","slug":"command-must-not-be-empty","errorCode":null,"errorMessage":"command must not be empty","messagePattern":"command must not be empty","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"studio/backend/routes/mcp_servers.py","lineNumber":80,"sourceCode":"def _validate_url(url: str) -> str:\n    trimmed = (url or \"\").strip()\n    if not trimmed:\n        raise HTTPException(status_code = 400, detail = \"url must not be empty\")\n    # When stdio is enabled, a non-HTTP value is a local command (reuses this\n    # field so stdio servers ride existing CRUD/storage).\n    if stdio_mcp_enabled() and is_stdio(trimmed):\n        try:\n            parts = parse_stdio_command(trimmed)\n        except ValueError as exc:\n            raise log_and_http_error(\n                exc,\n                400,\n                \"Invalid command. Check quoting and try again.\",\n                event = \"mcp_servers.invalid_command\",\n                log = logger,\n            )\n        if not parts or not parts[0].strip():\n            raise HTTPException(status_code = 400, detail = \"command must not be empty\")\n        if \"://\" in parts[0]:\n            # A URL-scheme first token is a mistyped URL, not a command. Reject\n            # cleanly instead of exec-ing it (mirrors the frontend check).\n            raise HTTPException(\n                status_code = 400,\n                detail = \"Enter an http(s):// URL, or a local command whose \"\n                \"first token is an executable (not a URL).\",\n            )\n        return trimmed\n    parsed = urlparse(trimmed)\n    if parsed.scheme not in (\"http\", \"https\"):\n        if _looks_like_command(trimmed):\n            detail = (\n                \"Local commands aren't enabled on this server. To allow them, \"\n                \"set UNSLOTH_STUDIO_ALLOW_STDIO_MCP=1 and restart Unsloth, or use \"\n                \"an http:// or https:// URL instead.\"\n            )\n        else:","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/mcp_servers.py#L62-L98","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Ensure the first whitespace-separated token is a real executable, e.g. 'npx -y @modelcontextprotocol/server-filesystem /path'.","Log/echo the exact string being sent before the request when building commands dynamically.","Add a client-side check that the trimmed command has at least one non-empty token."],"exampleFix":"# before\nclient.post('/api/mcp-servers/', json={'display_name': 'x', 'url': '   '})\n# with stdio enabled -> 400 'command must not be empty'\n\n# after\ncmd = ' '.join(part for part in [exe, *args] if part)\nassert cmd.split()[0], 'command executable missing'\nclient.post('/api/mcp-servers/', json={'display_name': 'x', 'url': cmd})","handlingStrategy":"validation","validationCode":"const parts = command.trim().split(/\\s+/);\nif (!parts[0] || !parts[0].trim()) throw new Error('Command needs an executable as its first token');","typeGuard":"function hasExecutable(cmd) { const t = (cmd ?? '').trim(); return t.length > 0 && t.split(/\\s+/)[0].length > 0; }","tryCatchPattern":null,"preventionTips":["Build command strings from filtered non-empty parts.","Reject all-whitespace or quote-only commands client-side."],"tags":["mcp","stdio","validation","http-400"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}