BerriAI/litellm · error · Exception

File not found. blocked_user_list={blocked_user_list}

Error message

File not found. blocked_user_list={blocked_user_list}

What it means

Thrown by the enterprise BlockedUserList hook constructor when blocked_user_list is a string (file path) and open() raises FileNotFoundError. Initialization fails fast so the proxy cannot start with a misconfigured blocklist path. The message includes the exact path that was not found.

Source

Thrown at enterprise/enterprise_hooks/blocked_user_list.py:39

    # Class variables or attributes
    def __init__(self, prisma_client: Optional[PrismaClient]):
        self.prisma_client = prisma_client

        blocked_user_list = litellm.blocked_user_list
        if blocked_user_list is None:
            self.blocked_user_list = None
            return

        if isinstance(blocked_user_list, list):
            self.blocked_user_list = blocked_user_list

        if isinstance(blocked_user_list, str):  # assume it's a filepath
            try:
                with open(blocked_user_list, "r") as file:
                    data = file.read()
                    self.blocked_user_list = data.split("\n")
            except FileNotFoundError:
                raise Exception(
                    f"File not found. blocked_user_list={blocked_user_list}"
                )
            except Exception as e:
                raise Exception(
                    f"An error occurred: {str(e)}, blocked_user_list={blocked_user_list}"
                )

    def print_verbose(self, print_statement, level: Literal["INFO", "DEBUG"] = "DEBUG"):
        if level == "INFO":
            verbose_proxy_logger.info(print_statement)
        elif level == "DEBUG":
            verbose_proxy_logger.debug(print_statement)

        if litellm.set_verbose is True:
            print(print_statement)  # noqa

    async def async_pre_call_hook(
        self,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Confirm the file exists at the exact path shown in the error, from the proxy process's working directory.
  2. Use an absolute path in the hook config to avoid CWD-relative resolution issues.
  3. In containers, verify the volume/secret mount and that the path in config matches the mounted path.
  4. Create the file (one user ID per line) if it is intentionally empty — an empty file is valid; a missing one is not.

Example fix

# before
blocked_user_list: ./blocked_users.txt

# after
blocked_user_list: /etc/litellm/blocked_users.txt
Defensive patterns

Strategy: validation

Validate before calling

import os

blocked_list_path = "/etc/litellm/blocked_users.txt"
if not os.path.isfile(blocked_list_path):
    raise SystemExit(f"missing blocklist file: {blocked_list_path}")

Try / catch

try:
    hook = BLOCKED_USER_LIST(blocked_user_list=path)
except Exception as e:
    if "File not found" in str(e):
        logger.error("blocklist missing at %s — creating empty file", path)
        Path(path).touch()  # explicit recovery choice
    raise

Prevention

When it happens

Trigger: Configuring the hook with blocked_user_list: "./blocked_users.txt" when the file does not exist at the proxy process's current working directory, an absolute path typo, or a file missing from a container image / unmounted secret volume.

Common situations: Docker/Kubernetes deployments where the blocklist file is mounted at a different path than configured, relative paths resolving differently between dev and prod, or the file simply never being created before first run.

Related errors


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