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

  1. Use /files/download/{flow_id}/{file_name} for non-image files instead of /files/images/...
  2. Ensure the file's final extension is a real image extension (.png, .jpg, .gif, .svg, .webp)
  3. 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

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


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/e54e0d4982dbe1d3. Report an issue: GitHub.