jamiepine/voicebox · warning · ValueError
Invalid image file: {str(e)}
Error message
Invalid image file: {str(e)} What it means
Returned by validate_image() when PIL.Image.open() or img.load() throws — the file could not be decoded as any image. The original exception string is embedded in the message. upload_avatar() re-raises it as a ValueError. Causes range from truncated/corrupt files to non-image files with an image extension.
Source
Thrown at backend/services/profiles.py:649
) -> VoiceProfileResponse:
"""
Upload and process avatar image for a profile.
Args:
profile_id: Profile ID
image_path: Path to uploaded image file
db: Database session
Returns:
Updated profile
"""
profile = db.query(DBVoiceProfile).filter_by(id=profile_id).first()
if not profile:
raise ValueError(f"Profile {profile_id} not found")
is_valid, error_msg = validate_image(image_path)
if not is_valid:
raise ValueError(error_msg)
if profile.avatar_path:
old_avatar = config.resolve_storage_path(profile.avatar_path)
if old_avatar is not None and old_avatar.exists():
old_avatar.unlink()
# Determine file extension from uploaded file
from PIL import Image
with Image.open(image_path) as img:
# Normalize JPEG variants (MPO is multi-picture format from some cameras)
img_format = img.format
if img_format in ("MPO", "JPG"):
img_format = "JPEG"
ext_map = {"PNG": ".png", "JPEG": ".jpg", "WEBP": ".webp"}
ext = ext_map.get(img_format, ".png")
View on GitHub (pinned to 51f49dea19)
Solutions
- Re-save or re-download the source image so it is a complete, valid file.
- Open the file locally with an image viewer or PIL to confirm it decodes before uploading.
- Install required PIL plugins for the source format (e.g. pip install pillow-heif for HEIC).
- Verify the multipart upload completes and that no proxy truncates the body.
Example fix
// before: file is truncated/corrupt -> 'Invalid image file: ...'
// after: validate locally first
from PIL import Image
try:
with Image.open('avatar.jpg') as im:
im.load() // raises if truncated
except Exception:
# re-export or re-download the source
... Defensive patterns
Strategy: validation
Validate before calling
from PIL import Image
def image_loads_cleanly(path: str) -> bool:
try:
with Image.open(path) as img:
img.load()
return True
except Exception:
return False Try / catch
try:
profile = await upload_avatar(profile_id, image_path, db)
except ValueError as e:
if 'Invalid image file' in str(e):
raise HTTPException(422, str(e))
raise Prevention
- Open/decode test the file locally with PIL before uploading.
- Ensure multipart uploads complete without truncation (proxy/buffer limits).
- Install required PIL plugins (e.g. pillow-heif) if you expect those source formats.
When it happens
Trigger: Uploading a truncated download (partial JPEG); a non-image file renamed to .jpg/.png; a zero-byte file; an image in a format PIL cannot decode without extra plugins (AVIF, HEIC without pillow-heif); a file corrupted in transit.
Common situations: Interrupted downloads; files renamed to spoof an extension; server-side buffer/truncation during multipart upload; clients sending the wrong file handle.
Related errors
- File size exceeds maximum of 5MB
- Invalid format '{img_format}'. Allowed formats: PNG, JPEG, W
- Profile not found: {profile_id}
- No samples found for profile {profile_id}
- HTTP error! status: ${response.status}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/fb735c436b3bab2b.
Report an issue: GitHub.