slimtoolkit / slimtoolkit/slim

Pillow with FastAPI broken after slimming (PIL.UnidentifiedImageError)

Open
#687 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

WIP
Dominant language
Go
Stars
23.4k
Forks
841
PR merge metrics
No merged PRs in 30d

Description

Expected Behavior

After slimming a container, Pillow throws a "PIL.UnidentifiedImageError" when reading an image. The code below is for an endpoint, but the behaviour is the same when reading from the file system. The code by itself is fine, as the not-slimmed container does work just fine. Similarly, reading an image from the file system using pillow that is not part of an FastAPI application works too in a slimmed container. Something about the combination slimmed container + FastAPI seems to break pillow.

Am I missing any shared libraries I have to specify manually or what could be the issue? Thanks already for the support!

from fastapi import FastAPI, File, UploadFile
from PIL import Image
from io import BytesIO
from pydantic import RootModel

app = FastAPI()

@app.post("/upload")
async def put_object(file: UploadFile = File(...)):
    request_object_content = await file.read()
    img = Image.open(BytesIO(request_object_content))
    
    width, height = img.size
    return {"width": width, "height": height}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Actual Behavior

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py", line 399, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/usr/local/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 70, in __call__
    return await self.app(scope, receive, send)
  File "/usr/local/lib/python3.9/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.9/site-packages/starlette/applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.9/site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "/usr/local/lib/python3.9/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 65, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/usr/local/lib/python3.9/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/usr/local/lib/python3.9/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 297, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 77, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/usr/local/lib/python3.9/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/usr/local/lib/python3.9/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 72, in app
    response = await func(request)
  File "/usr/local/lib/python3.9/site-packages/fastapi/routing.py", line 278, in app
    raw_response = await run_endpoint_function(
  File "/usr/local/lib/python3.9/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
    return await dependant.call(**values)
  File "/app/main.py", line 11, in put_object
    img = Image.open(BytesIO(request_object_content))
  File "/usr/local/lib/python3.9/site-packages/PIL/Image.py", line 3339, in open
    raise UnidentifiedImageError(msg)
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0xffff82157d10>

Steps to Reproduce the Problem

  1. paste code above in main.py
  2. execute: slim --crt-api-version=1.25 build --dockerfile Dockerfile --include-exe tesseract --include-path /app --tag-fat test-container . (don't forget to delete the ".txt" from the attached Dockerfile...)
  3. start container with docker run -it -p 8000:8000 test-container.slim
  4. open http://0.0.0.0:8000/docs in the browser
  5. upload an image (jpeg/png) in the /upload section of the swagger documentation

Specifications

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with main.py, Dockerfile.txt, and requirements.txt, then reproduce the upload through the FastAPI /upload endpoint using the provided slim build command and compare it with the non-slimmed container. Check whether the slim image preserves the dependencies needed for Pillow to identify JPEG and PNG files; done means image uploads work in the slim container without the reported exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, fastapi, python
Domain
backend, devops, infrastructure
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.