{"record":{"id":"e54e0d4982dbe1d3","repo":"langflow-ai/langflow","slug":"content-type-content-type-is-not-an-image","errorCode":null,"errorMessage":"Content type {content_type} is not an image","messagePattern":"Content type (.+?) is not an image","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"src/backend/base/langflow/api/v1/files.py","lineNumber":178,"sourceCode":"    # Security: resolve flow through get_flow so image access requires authentication and owner match.\n    flow: Annotated[Flow, Depends(get_flow)],\n    storage_service: Annotated[StorageService, Depends(get_storage_service)],\n):\n    \"\"\"Download image from storage for browser rendering.\"\"\"\n    extension = file_name.split(\".\")[-1]\n    flow_id_str = str(flow.id)\n\n    if not extension:\n        raise HTTPException(status_code=500, detail=f\"Extension not found for file {file_name}\")\n    try:\n        content_type = build_content_type_from_extension(extension)\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e)) from e\n\n    if not content_type:\n        raise HTTPException(status_code=500, detail=f\"Content type not found for extension {extension}\")\n    if not content_type.startswith(\"image\"):\n        raise HTTPException(status_code=500, detail=f\"Content type {content_type} is not an image\")\n\n    try:\n        file_content = await storage_service.get_file(flow_id=flow_id_str, file_name=file_name)\n        # Defense-in-depth: a tenant-uploaded SVG/HTML served inline with a renderable content type\n        # would execute scripts in the app origin if opened directly. nosniff stops MIME sniffing\n        # and Content-Disposition: attachment forces a download on direct navigation (so any script\n        # cannot run in-origin). <img>/blob embedding -- the intended use -- is unaffected.\n        return StreamingResponse(\n            BytesIO(file_content),\n            media_type=content_type,\n            headers={\"X-Content-Type-Options\": \"nosniff\", \"Content-Disposition\": \"attachment\"},\n        )\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e)) from e\n\n\n@router.get(\"/profile_pictures/{folder_name}/{file_name}\")\nasync def download_profile_picture(","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/files.py#L160-L196","documentation":"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.","triggerScenarios":"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).","commonSituations":"Frontends reusing the images URL pattern for all attachments; renamed files where the final extension no longer reflects an image.","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"],"exampleFix":"# before\nGET /files/images/{flow_id}/2024-01-01_report.pdf\n\n# after\nGET /files/download/{flow_id}/2024-01-01_report.pdf","handlingStrategy":"type-guard","validationCode":"IMAGE_PREFIX = (\".png\", \".jpg\", \".jpeg\", \".gif\", \".svg\", \".webp\")\n\ndef is_image_file_name(file_name: str) -> bool:\n    return file_name.lower().endswith(IMAGE_PREFIX)","typeGuard":"function isImageFileName(fileName: string): boolean {\n  return /\\.(png|jpe?g|gif|svg|webp)$/i.test(fileName);\n}","tryCatchPattern":"try:\n    client.get(f\"/files/images/{flow_id}/{file_name}\").raise_for_status()\nexcept HTTPError as e:\n    if \"not an image\" in e.response.text:\n        client.get(f\"/files/download/{flow_id}/{file_name}\")  # correct route\n    raise","preventionTips":["Route by content: /files/images for images, /files/download for everything else","Never assume the images endpoint is a generic file server"],"tags":["files","images","mime-type","http-500"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}