unslothai/unsloth · error · ValueError

extra llama-server args cannot contain control characters

Error message

extra llama-server args cannot contain control characters

What it means

ValueError from llama_server_args.py:271 — a token in the extra args contains control characters (via _has_control_characters). execve rejects NUL outright, and other invisible characters would pass through to llama-server's parser and be blamed on whatever flag they are attached to, producing confusing 'invalid argument' errors at spawn time. Refused early as a 400.

Source

Thrown at studio/backend/core/inference/llama_server_args.py:271

        # is on the whole list rather than per token.
        # Strictly, unlike the sizing below: JSON and the browser can both carry an
        # unpaired surrogate, which survives every check here and then makes
        # subprocess.Popen raise while it encodes argv, long after the load has begun
        # switching models. Refused at the boundary, where it is still a 400.
        try:
            encoded = token.encode("utf-8")
        except UnicodeEncodeError as error:
            raise ValueError(
                "extra llama-server args cannot contain unpaired surrogate characters"
            ) from error
        total_bytes += len(encoded)
        limit = max_extra_args_bytes()
        if total_bytes > limit:
            raise ValueError(f"extra llama-server args are too large (limit {limit} bytes)")
        # execve rejects a NUL outright; the rest would reach the child's parser as
        # invisible characters and be blamed on the flag they are attached to.
        if _has_control_characters(token):
            raise ValueError("extra llama-server args cannot contain control characters")
        flag = _flag_name(token)
        if flag is not None and flag in _DENYLIST:
            raise ValueError(
                f"llama-server flag '{flag}' is managed by Unsloth Studio "
                f"and cannot be passed as an extra arg"
            )
        if flag is None:
            # A token belonging to no flag. Today's llama-server answers "invalid
            # argument" and refuses to start, which is a failed load rather than a
            # 400, and a build that did accept a positional would read it as the
            # model path: that is the one thing the -m / --model denial exists to
            # prevent, and it would sidestep the native-path lease as well.
            if pending_values <= 0:
                raise ValueError(
                    "extra llama-server args cannot contain a bare value "
                    f"('{token[:64]}'); every value must follow its flag"
                )
            pending_values -= 1

View on GitHub (pinned to 203007d190)

Solutions

  1. Flatten multi-line shell commands into one line before submitting: remove backslash-newline continuations.
  2. Strip control characters from each token before submit: ''.join(c for c in t if unicodedata.category(c) != 'Cc').
  3. If a value legitimately needs newlines (e.g. a chat template), pass it via a file path instead of inline argv.
  4. Inspect for hidden characters: repr(token) or [hex(ord(c)) for c in token] to find the offending byte.

Example fix

# before
raw = "--chat-template\\\n  {{...}}"  # backslash-newline continuation survives
args = raw.split()

# after
args = [t for line in raw.splitlines() for t in line.split()]  # clean flatten
# or: args = [strip_controls(t) for t in args]
Defensive patterns

Strategy: validation

Validate before calling

def has_control_chars(s) -> bool:
    return any(unicodedata.category(c) == 'Cc' for c in s)
# reject before submit:
assert not any(has_control_chars(t) for t in extra_args)

Type guard

def is_control_free(s) -> bool:
    return all(unicodedata.category(c) != 'Cc' for c in s)

Try / catch

try:
    validate_extra_args(args)
except ValueError as e:
    if "control characters" in str(e):
        args = [''.join(c for c in t if ord(c) >= 32) for t in args]
        validate_extra_args(args)
    else:
        raise

Prevention

When it happens

Trigger: Extra args containing \x00, \r, \n, \t, or other C0/C1 control codes — usually from copy-pasting a multi-line shell command where line continuations or newlines survive into a single token, or from programmatic arg building that includes raw control bytes.

Common situations: Pasting a shell snippet with backslash-newline continuations into the extra-args UI; a config file with Windows CRLF line endings parsed so \r rides along on the last token of each line; a chat template containing literal \n inside a token (values are also checked).

Related errors


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