Skip to content

[Bug]: non_root image missing /app/enterprise — "Managed files hook not found" on POST /v1/files (fix exists in main, needs backport to stable) #38183

Description

@alexhuk3

Check for existing issues

  • I have searched the existing issues and checked that my issue is not a duplicate.

What happened?

On the hardened image ghcr.io/berriai/litellm-non_root (reproduced on main-v1.81.3-stable and main-v1.81.9-stable), every managed-files upload fails with HTTP 500
{"error":{"message":"Managed files hook not found",...}}. The identical request against the regular image ghcr.io/berriai/litellm:v1.81.3-stable — same config.yaml, same
database, same request — succeeds. Reads (GET /v1/files) work on both images; only the write path is broken.

Root cause (verified): litellm/proxy/hooks/__init__.py registers enterprise hooks via from enterprise.enterprise_hooks import ENTERPRISE_PROXY_HOOKS inside try/except ImportError that silently swallows the failure. The enterprise package is a top-level repo directory that is importable only because proxy_cli.py does
sys.path.append(os.getcwd()) with WORKDIR /app:

  • regular Dockerfile runtime stage: COPY . ./app/enterprise exists → hook registers;
  • docker/Dockerfile.non_root runtime stage copies only selected paths and never copies /app/enterprise → silent ImportError → managed_files missing from PROXY_HOOKS → 500
    on every write.

Inside a running non_root container:

$ python3 -c "import enterprise"   # ModuleNotFoundError
$ python3 -c "from litellm.proxy.hooks import PROXY_HOOKS; print(sorted(PROXY_HOOKS))"
['cache_control_check', 'litellm_skills', 'max_budget_limiter', 'parallel_request_limiter', 'responses_id_security']

The fix already exists in main: docker/Dockerfile.non_root line ~141 has COPY --from=builder /app/enterprise /app/enterprise (present in source tags ≥ v1.90.0). But the
newest published non_root stable image (main-v1.81.9-stable) predates it, so all published non_root stable images ship broken. Request: backport that COPY to the stable line
/ rebuild stable non_root images.
Also consider logging a warning instead of silently swallowing the ImportError — it would make this a 5-minute diagnosis.

Expected: POST /v1/files with target_model_names behaves identically on both image variants.

Related but distinct: #32782 (missing litellm_enterprise pip package in another context).

User Flow

Before a (hypothetical) fix: an automation engineer uploading a video for Gemini analysis through a gateway running the hardened non_root image gets a 500 on every upload

  1. They send POST https://litellm-domain/v1/files as multipart with file=@video.mp4, purpose=user_data, target_model_names=gemini-2.5-flash
  2. The response is HTTP 500 with body {"error":{"message":"Managed files hook not found","type":"None","param":"None","code":"500"}}
  3. They send GET https://litellm-domain/v1/files and get 200 with a normal (empty) file list, so reads clearly work
  4. They retry the exact same POST against a gateway running the regular (root) image with the same configuration and get 200 with a unified file id — so their request is valid and
    only the hardened image rejects it

After a (hypothetical) fix: the same upload on the hardened non_root image succeeds like on the regular image

  1. They send the same POST https://litellm-domain/v1/files as multipart with file=@video.mp4, purpose=user_data, target_model_names=gemini-2.5-flash
  2. The response is HTTP 200 with a unified file id in the body
  3. GET https://litellm-domain/v1/files returns 200 and now lists the uploaded file
  4. A follow-up chat completion referencing that file id runs against gemini-2.5-flash and returns normally

Proof the bug occurs

Config / setup the proxy ran with:

# config.yaml
general_settings:
  master_key: sk-REDACTED
  database_url: os.environ/DATABASE_URL   # local postgres, e.g. postgresql://litellm:***@localhost:5432/litellm
model_list:
  - model_name: gemini-2.5-flash
    litellm_params:
      model: gemini/gemini-2.5-flash
      api_key: os.environ/GEMINI_API_KEY

Version or commit: images ghcr.io/berriai/litellm-non_root:main-v1.81.9-stable (broken) vs ghcr.io/berriai/litellm:v1.81.3-stable (works)

Commands and their full output:

# 1) broken: non_root image
docker run --rm -p 4000:4000 --network host \
  -e DATABASE_URL=postgresql://litellm:REDACTED@localhost:5432/litellm \
  -e GEMINI_API_KEY=REDACTED \
  -v $PWD/config.yaml:/app/config.yaml \
  ghcr.io/berriai/litellm-non_root:main-v1.81.9-stable --config /app/config.yaml --port 4000
  
curl -sS -X POST http://localhost:4000/v1/files \
  -H "Authorization: Bearer sk-REDACTED" \
  -F purpose=user_data -F target_model_names=gemini-2.5-flash -F file=@video.mp4
# → <вставь реальный ответ: HTTP 500 Managed files hook not found>

# 2) supporting evidence — the module is physically absent in the image:
docker exec <container> python3 -c "import enterprise"
# → ModuleNotFoundError: No module named 'enterprise'

# 3) works: regular image, same config, same DB, same curl
docker run ... ghcr.io/berriai/litellm:v1.81.3-stable --config /app/config.yaml --port 4000
curl  (same as above)
# → <вставь реальный ответ: 200 + file id>

What part of LiteLLM is this about?

Other

What LiteLLM version are you on ?

v1.81.3-stable

Twitter / LinkedIn details

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions