unslothai/unsloth · critical · ValueError

Unsloth MCP bearer token must be a non-empty value

Error message

Unsloth MCP bearer token must be a non-empty value

What it means

ValueError from BearerTokenMiddleware.__init__ when the token passed for the Unsloth MCP app is empty or whitespace-only. The middleware performs exact bearer-token authentication on every HTTP/websocket request, so an empty token would either match nothing or (worse) trivially guessable values; construction fails fast instead.

Source

Thrown at studio/backend/mcp_server.py:25

duplicating training or export logic. It is opt-in because several tools can
start GPU work or write model artifacts.
"""

from __future__ import annotations

import hmac
import asyncio
from typing import Any

from fastmcp import FastMCP


class BearerTokenMiddleware:
    """Require an exact bearer token when Unsloth MCP is exposed remotely."""

    def __init__(self, app: Any, token: str) -> None:
        if not token or not token.strip():
            raise ValueError("Unsloth MCP bearer token must be a non-empty value")
        if not token.isascii():
            # A non-ASCII token cannot be sent in an HTTP header; reject it here.
            raise ValueError("Unsloth MCP bearer token must contain ASCII characters only")
        self.app = app
        # Compare on raw header bytes: str hmac.compare_digest raises on non-ASCII
        # input, which would surface as a 500 instead of a clean 401.
        self.expected = token.encode("utf-8")

    async def __call__(self, scope: dict[str, Any], receive: Any, send: Any) -> None:
        scope_type = scope.get("type")
        if scope_type not in ("http", "websocket"):
            await self.app(scope, receive, send)
            return

        headers = dict(scope.get("headers", []))
        raw_auth = headers.get(b"authorization", b"")
        scheme, _, supplied = raw_auth.partition(b" ")
        if scheme.lower() != b"bearer" or not hmac.compare_digest(supplied, self.expected):

View on GitHub (pinned to 203007d190)

Solutions

  1. Set UNSLOTH_STUDIO_MCP_TOKEN to a non-empty, non-whitespace ASCII secret before starting the backend.
  2. Generate one with 'openssl rand -hex 32' and inject it via your secret manager.
  3. If MCP was enabled accidentally, unset UNSLOTH_STUDIO_ENABLE_MCP.

Example fix

# before
export UNSLOTH_STUDIO_MCP_TOKEN=""
# after
export UNSLOTH_STUDIO_MCP_TOKEN="$(openssl rand -hex 32)"
Defensive patterns

Strategy: validation

Validate before calling

def valid_mcp_token(token: str | None) -> bool:
    return bool(token) and bool(token.strip())

Type guard

def is_nonempty_token(t: str | None) -> bool:
    return isinstance(t, str) and t.strip() != ""

Prevention

When it happens

Trigger: Constructing BearerTokenMiddleware(app, token='') or BearerTokenMiddleware(app, token=' '), typically indirectly because main.py read an empty UNSLOTH_STUDIO_MCP_TOKEN from the environment while UNSLOTH_STUDIO_ENABLE_MCP=1.

Common situations: Secrets file that defines the key with an empty value; YAML/env templating that strips the token; CI enabling MCP without provisioning a token.

Related errors


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