unslothai/unsloth · critical · ValueError

Unsloth MCP bearer token must contain ASCII characters only

Error message

Unsloth MCP bearer token must contain ASCII characters only

What it means

ValueError from BearerTokenMiddleware.__init__ when the supplied MCP bearer token contains non-ASCII characters. HTTP header values cannot carry non-ASCII bytes, and the middleware later compares raw header bytes with hmac.compare_digest, which raises on non-ASCII str input — so a non-ASCII token is rejected up front with a clear message instead of a 500 during a request.

Source

Thrown at studio/backend/mcp_server.py:28

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):
            await _send_unauthorized(send, scope_type)
            return

View on GitHub (pinned to 203007d190)

Solutions

  1. Replace the token with a pure-ASCII secret, e.g. output of 'openssl rand -hex 32'.
  2. Re-type or re-paste the value in a plain-text editor to strip invisible Unicode (smart quotes, NBSP, BOM).
  3. Verify with: python -c "import os; print(os.environ['UNSLOTH_STUDIO_MCP_TOKEN'].isascii())" -> True.

Example fix

# before
export UNSLOTH_STUDIO_MCP_TOKEN='pässphrase-é'
# 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 (
        isinstance(token, str)
        and token.strip() != ""
        and token.isascii()
    )

Type guard

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

Prevention

When it happens

Trigger: Setting UNSLOTH_STUDIO_MCP_TOKEN to a string with non-ASCII characters (e.g. a passphrase with 'é', emoji, or CJK characters), or a copy/paste from a document that introduced a smart quote or invisible Unicode character.

Common situations: Human-chosen passphrases in non-English locales; tokens pasted from rich-text editors that normalize quotes; files saved with a BOM or non-breaking space included in the value.

Related errors


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