{"record":{"id":"005085253452564a","repo":"BerriAI/litellm","slug":"file-id-must-reference-a-litellm-managed-storage-o","errorCode":null,"errorMessage":"file_id must reference a LiteLLM-managed storage object","messagePattern":"file_id must reference a LiteLLM-managed storage object","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/cloud_storage_security.py","lineNumber":167,"sourceCode":"    bucket_name, object_name = full_path.split(\"/\", 1)\n    configured_bucket, configured_prefix = split_configured_cloud_bucket_name(configured_bucket_name)\n    if bucket_name != configured_bucket:\n        raise ValueError(\"file_id bucket does not match the configured storage bucket\")\n\n    _validate_cloud_object_path(object_name)\n    allowed_prefixes = tuple(allowed_object_prefixes)\n    if configured_prefix:\n        allowed_prefixes = tuple(f\"{configured_prefix.rstrip('/')}/{prefix}\" for prefix in allowed_prefixes)\n\n    if object_name.startswith(allowed_prefixes):\n        return bucket_name, object_name\n\n    if allow_legacy_cloud_file_ids:\n        if configured_prefix and not object_name.startswith(f\"{configured_prefix.rstrip('/')}/\"):\n            raise ValueError(\"file_id object does not match the configured storage prefix\")\n        return bucket_name, object_name\n\n    raise ValueError(\"file_id must reference a LiteLLM-managed storage object\")\n","sourceCodeStart":149,"sourceCodeEnd":168,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/cloud_storage_security.py#L149-L168","documentation":"The final guard of validate_managed_cloud_file_id: the object name does not start with any allowed prefix (each optionally nested under the configured bucket prefix) and legacy ids are not permitted, so the URI — though structurally valid and in the right bucket — does not reference a LiteLLM-managed storage object. This is the core anti-confusion check stopping clients from making the proxy read arbitrary keys in the bucket.","triggerScenarios":"file_id = 'gs://my-bucket/backups/db.dump' when the only allowed prefix is 'litellm/' (and allow_legacy_cloud_file_ids is False/default); passing hand-crafted URIs naming keys uploaded outside litellm's file management.","commonSituations":"Attempting to reuse objects uploaded directly via gsutil/console with litellm file endpoints; pentest/probing requests trying to read arbitrary keys; misconfigured allowed_object_prefixes that no longer matches where files are actually written.","solutions":["Upload or register the file through litellm's managed file flow so it lands under an allowed prefix and returns a valid id.","If the object is legitimate, add its folder to the deployment's allowed object prefixes (or move the object under an existing allowed prefix).","As a migration measure only, enable allow_legacy_cloud_file_ids if your version exposes it — understanding this widens what the proxy will read."],"exampleFix":"# before\nfile_id = \"gs://my-bucket/random/key.json\"    # outside allowed prefix 'litellm/'\n\n# after\n# register through litellm file management, then use the returned id:\nfile_id = \"gs://my-bucket/litellm/managed-key.json\"","handlingStrategy":"validation","validationCode":"def under_allowed_prefixes(file_id: str, configured: str, allowed: tuple[str, ...], scheme: str = \"gs://\") -> bool:\n    cfg_bucket, _, cfg_prefix = configured.strip().partition(\"/\")\n    bucket, obj = unquote(file_id)[len(scheme):].split(\"/\", 1)\n    prefixes = tuple(f\"{cfg_prefix.rstrip('/')}/{p}\" for p in allowed) if cfg_prefix else allowed\n    return bucket == cfg_bucket and obj.startswith(prefixes)","typeGuard":"def is_managed_object_reference(v: object, configured: str, allowed: tuple[str, ...], scheme: str = \"gs://\") -> bool:\n    if not isinstance(v, str):\n        return False\n    try:\n        bucket, obj = unquote(v)[len(scheme):].split(\"/\", 1)\n    except ValueError:\n        return False\n    cfg_bucket, _, cfg_prefix = configured.strip().partition(\"/\")\n    prefixes = tuple(f\"{cfg_prefix.rstrip('/')}/{p}\" for p in allowed) if cfg_prefix else allowed\n    return bucket == cfg_bucket and obj.startswith(prefixes)","tryCatchPattern":"try:\n    validate_managed_cloud_file_id(fid, scheme, cfg, allowed_prefixes)\nexcept ValueError as e:\n    if \"LiteLLM-managed\" in str(e):\n        return HTTP 403  # client tried to reference a non-managed key; never auto-widen prefixes","preventionTips":["Only reference files created through litellm's managed upload flow.","Keep allowed_object_prefixes in sync with where your code writes objects.","Treat this error as a security signal (potential arbitrary-key read attempt) and alert on it."],"tags":["file-upload","cloud-storage","security","prefix","access-control"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}