{"record":{"id":"eec5d00c92254d51","repo":"BerriAI/litellm","slug":"cloud-storage-bucket-name-contains-control-charact","errorCode":null,"errorMessage":"Cloud storage bucket name contains control characters","messagePattern":"Cloud storage bucket name contains control characters","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/cloud_storage_security.py","lineNumber":95,"sourceCode":"        raise ValueError(\"Cloud storage object name must be relative\")\n    if any(ord(char) < 32 or ord(char) == 127 for char in object_name):\n        raise ValueError(\"Cloud storage object name contains control characters\")\n    segments: Final = object_name.split(\"/\")\n    if any(segment in {\".\", \"..\"} for segment in segments):\n        raise ValueError(\"Cloud storage object name contains an invalid path segment\")\n    if \"\" in segments[:-1]:\n        raise ValueError(\"Cloud storage object name contains an invalid path segment\")\n\n\ndef split_configured_cloud_bucket_name(bucket_name: str) -> tuple[str, str]:\n    if not isinstance(bucket_name, str) or not bucket_name.strip():\n        raise ValueError(\"Cloud storage bucket name is required\")\n\n    bucket_name = bucket_name.strip()\n    if \"://\" in bucket_name or \"?\" in bucket_name or \"#\" in bucket_name:\n        raise ValueError(\"Cloud storage bucket name must not include a URI scheme or query\")\n    if any(ord(char) < 32 or ord(char) == 127 for char in bucket_name):\n        raise ValueError(\"Cloud storage bucket name contains control characters\")\n\n    bucket, _, prefix = bucket_name.partition(\"/\")\n    if not bucket:\n        raise ValueError(\"Cloud storage bucket name is required\")\n    if \"\\\\\" in bucket:\n        raise ValueError(\"Cloud storage bucket name contains an invalid separator\")\n\n    prefix = prefix.strip(\"/\")\n    if prefix:\n        _validate_cloud_object_path(prefix)\n\n    return bucket, prefix\n\n\ndef encode_gcs_object_name_for_url(object_name: str) -> str:\n    return quote(unquote(object_name), safe=\"\")\n\n","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/cloud_storage_security.py#L77-L113","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","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).","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."],"exampleFix":"# before (docker-compose, accidental newline)\nenvironment:\n  - GCS_BUCKET=my-bucket\\n   # trailing newline from YAML\n\n# after\nenvironment:\n  - GCS_BUCKET=my-bucket","handlingStrategy":"validation","validationCode":"def has_control_chars(s: str) -> bool:\n    return any(ord(c) < 32 or ord(c) == 127 for c in s)\n\nif has_control_chars(os.environ[\"GCS_BUCKET\"]):\n    raise RuntimeError(\"GCS_BUCKET contains control characters; re-enter as a single line\")","typeGuard":"def is_control_char_free(value: object) -> bool:\n    return isinstance(value, str) and not any(ord(c) < 32 or ord(c) == 127 for c in value)","tryCatchPattern":"try:\n    split_configured_cloud_bucket_name(cfg)\nexcept ValueError as e:\n    if \"control characters\" in str(e):\n        cfg = \"\".join(c for c in cfg if ord(c) >= 32 and ord(c) != 127)  # log & fix source instead\n    raise","preventionTips":["Create secrets with --from-literal, not from CRLF-bearing files.","Add a lint step over env files flagging non-printable bytes.","Prefer editor 'show whitespace' when editing config values."],"tags":["cloud-storage","config","control-characters","encoding","gcs"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}