Why does it work in the container but fail in Odoo?
When you run code in Odoo:
• Odoo may monkey-patch certain libraries (e.g., requests, image handling, base64 encoding).
• Odoo often runs under a different user, environment variables, or restricted execution context than the interactive Python shell.
• The io.BytesIO object or file pointer may be altered (e.g., closed, truncated, or empty) before Image.open() reads it.
Possible causes
Truncated or altered content
• Odoo’s import mechanism may manipulate the content before passing it to Pillow.
• If iter_content or content is re-read multiple times, the BytesIO buffer can be empty.
Pillow plugin mismatch
• The same Pillow version (11.2.1) is reported, but Odoo could be running with disabled or missing WebP plugin if Pillow was compiled differently.
• Some Odoo workers could be using a system-level Pillow without WebP support.
Different error handling for WebP
• Odoo’s image processing pipeline sometimes pre-converts images (e.g., using base64, tools.image_process). This can strip unsupported formats.
Threaded environment or lazy loading
• In multi-threaded environments, race conditions on BytesIO can cause UnidentifiedImageError.
Debugging steps
A. Check the content length inside Odoo
Before Image.open, verify if the buffer has data:
print(len(content))
If 0, the buffer is empty when Odoo executes it.
B. Save the file temporarily to check integrity
with open("/tmp/test.webp", "wb") as f:
f.write(content)
Then manually run Image.open("/tmp/test.webp"). If it opens, Odoo is altering BytesIO.
C. Explicitly load and verify the image
image = Image.open(io.BytesIO(content))
image.load() # Force full loading
image.verify()
This can help pinpoint lazy loading issues.
D. Check Pillow features at runtime inside Odoo
from PIL import features
print("WebP support:", features.check('webp'))
If this returns False inside Odoo, it’s a plugin issue.
4. Fixes
Option 1: Ensure content is not re-read
When using iter_content, ensure the stream isn’t consumed twice:
res = requests.get(url, stream=True)
content = res.content # instead of iter_content
image = Image.open(io.BytesIO(content))
Option 2: Upgrade or recompile Pillow with WebP support
Ensure Pillow in the container supports WebP:
apt-get install libwebp-dev
pip install --force-reinstall pillow
Option 3: Use Odoo’s own image tools (avoiding direct Image.open)
Odoo provides tools.image_process which handles WebP gracefully (it may auto-convert to PNG):
from odoo.tools import image_process
image_data = image_process(content)
Option 4: Patch Odoo import code
If Odoo’s import pipeline uses BytesIO incorrectly, add a copy:
buffer = io.BytesIO(content)
buffer.seek(0)
image = Image.open(buffer)
5. Why is it only failing for WebP?
• WebP images are more sensitive to truncation; a small byte mismatch can make Pillow fail.
• Odoo sometimes converts WebP → PNG using an intermediate library, and if this fails silently, you’ll get an empty buffer.
Did you solved the issue? If so, please share.