langflow-ai/langflow · error · HTTPException
Content type {content_type} is not an image
Error message
Content type {content_type} is not an image What it means
HTTP 500 from GET /files/images/{flow_id}/{file_name} when the resolved content type does not start with 'image' (e.g. text/plain, application/pdf). The images endpoint is strictly for image rendering; it refuses to stream non-image bytes even though the file exists, preventing the browser-rendering route from serving arbitrary content types.
Source
Thrown at src/backend/base/langflow/api/v1/files.py:178
# Security: resolve flow through get_flow so image access requires authentication and owner match.
flow: Annotated[Flow, Depends(get_flow)],
storage_service: Annotated[StorageService, Depends(get_storage_service)],
):
"""Download image from storage for browser rendering."""
extension = file_name.split(".")[-1]
flow_id_str = str(flow.id)
if not extension:
raise HTTPException(status_code=500, detail=f"Extension not found for file {file_name}")
try:
content_type = build_content_type_from_extension(extension)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if not content_type:
raise HTTPException(status_code=500, detail=f"Content type not found for extension {extension}")
if not content_type.startswith("image"):
raise HTTPException(status_code=500, detail=f"Content type {content_type} is not an image")
try:
file_content = await storage_service.get_file(flow_id=flow_id_str, file_name=file_name)
# Defense-in-depth: a tenant-uploaded SVG/HTML served inline with a renderable content type
# would execute scripts in the app origin if opened directly. nosniff stops MIME sniffing
# and Content-Disposition: attachment forces a download on direct navigation (so any script
# cannot run in-origin). <img>/blob embedding -- the intended use -- is unaffected.
return StreamingResponse(
BytesIO(file_content),
media_type=content_type,
headers={"X-Content-Type-Options": "nosniff", "Content-Disposition": "attachment"},
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/profile_pictures/{folder_name}/{file_name}")
async def download_profile_picture(View on GitHub (pinned to 976ec789d2)
Solutions
- Use /files/download/{flow_id}/{file_name} for non-image files instead of /files/images/...
- Ensure the file's final extension is a real image extension (.png, .jpg, .gif, .svg, .webp)
- Strip misleading double extensions when storing files
Example fix
# before
GET /files/images/{flow_id}/2024-01-01_report.pdf
# after
GET /files/download/{flow_id}/2024-01-01_report.pdf Defensive patterns
Strategy: type-guard
Validate before calling
IMAGE_PREFIX = (".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp")
def is_image_file_name(file_name: str) -> bool:
return file_name.lower().endswith(IMAGE_PREFIX) Type guard
function isImageFileName(fileName: string): boolean {
return /\.(png|jpe?g|gif|svg|webp)$/i.test(fileName);
} Try / catch
try:
client.get(f"/files/images/{flow_id}/{file_name}").raise_for_status()
except HTTPError as e:
if "not an image" in e.response.text:
client.get(f"/files/download/{flow_id}/{file_name}") # correct route
raise Prevention
- Route by content: /files/images for images, /files/download for everything else
- Never assume the images endpoint is a generic file server
When it happens
Trigger: Requesting /files/images/... for a .txt, .pdf, .csv, or .json file stored in the flow's folder; files with double extensions where the last one maps to a non-image type (image.png.txt).
Common situations: Frontends reusing the images URL pattern for all attachments; renamed files where the final extension no longer reflects an image.
Related errors
- Content type not found for extension {extension}
- str(e)
- {str(e)}
- Extension not found for file {file_name}
- HTTP error! status: ${response.status}
AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14).
Data as JSON: /api/errors/e54e0d4982dbe1d3.
Report an issue: GitHub.