BerriAI/litellm · error · ValueError

Cloud storage bucket name contains control characters

Error message

Cloud storage bucket name contains control characters

What it means

Raised by split_configured_cloud_bucket_name when any character of the configured bucket name has an ordinal below 32 or equal to 127 — i.e. ASCII control characters such as newline, tab, or carriage return. Control characters in bucket names are invalid for cloud providers and often indicate a copy-paste or env-file formatting accident, so litellm rejects them before any network call.

Source

Thrown at litellm/litellm_core_utils/cloud_storage_security.py:95

        raise ValueError("Cloud storage object name must be relative")
    if any(ord(char) < 32 or ord(char) == 127 for char in object_name):
        raise ValueError("Cloud storage object name contains control characters")
    segments: Final = object_name.split("/")
    if any(segment in {".", ".."} for segment in segments):
        raise ValueError("Cloud storage object name contains an invalid path segment")
    if "" in segments[:-1]:
        raise ValueError("Cloud storage object name contains an invalid path segment")


def split_configured_cloud_bucket_name(bucket_name: str) -> tuple[str, str]:
    if not isinstance(bucket_name, str) or not bucket_name.strip():
        raise ValueError("Cloud storage bucket name is required")

    bucket_name = bucket_name.strip()
    if "://" in bucket_name or "?" in bucket_name or "#" in bucket_name:
        raise ValueError("Cloud storage bucket name must not include a URI scheme or query")
    if any(ord(char) < 32 or ord(char) == 127 for char in bucket_name):
        raise ValueError("Cloud storage bucket name contains control characters")

    bucket, _, prefix = bucket_name.partition("/")
    if not bucket:
        raise ValueError("Cloud storage bucket name is required")
    if "\\" in bucket:
        raise ValueError("Cloud storage bucket name contains an invalid separator")

    prefix = prefix.strip("/")
    if prefix:
        _validate_cloud_object_path(prefix)

    return bucket, prefix


def encode_gcs_object_name_for_url(object_name: str) -> str:
    return quote(unquote(object_name), safe="")

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Re-enter the value ensuring a single line with no leading/trailing whitespace; note the earlier .strip() removes outer spaces but NOT embedded \n/\t, so remove them from the source.
  2. If the value comes from a secret store, re-create the secret with a clean single-line string (kubectl create secret --from-literal rather than a file with CRLF).
  3. Sanitize at read time: bucket_name.replace('\r','').replace('\n','').replace('\t','') before passing to litellm, or better, fail loudly if control chars are detected.

Example fix

# before (docker-compose, accidental newline)
environment:
  - GCS_BUCKET=my-bucket\n   # trailing newline from YAML

# after
environment:
  - GCS_BUCKET=my-bucket
Defensive patterns

Strategy: validation

Validate before calling

def has_control_chars(s: str) -> bool:
    return any(ord(c) < 32 or ord(c) == 127 for c in s)

if has_control_chars(os.environ["GCS_BUCKET"]):
    raise RuntimeError("GCS_BUCKET contains control characters; re-enter as a single line")

Type guard

def is_control_char_free(value: object) -> bool:
    return isinstance(value, str) and not any(ord(c) < 32 or ord(c) == 127 for c in value)

Try / catch

try:
    split_configured_cloud_bucket_name(cfg)
except ValueError as e:
    if "control characters" in str(e):
        cfg = "".join(c for c in cfg if ord(c) >= 32 and ord(c) != 127)  # log & fix source instead
    raise

Prevention

When it happens

Trigger: A trailing '\n' inside a quoted env value (GCS_BUCKET="my-bucket\n" in some .env parsers), a tab between bucket and prefix ('my-bucket\t/logs'), or invisible characters injected by a CI secret. any(ord(c) < 32 ...) then trips immediately.

Common situations: Multi-line values in docker-compose or Kubernetes secrets where YAML folding adds \n; values copied from rich-text docs/Slack carrying non-printing bytes; Windows CRLF line endings leaking \r into the variable.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/eec5d00c92254d51. Report an issue: GitHub.