-
Notifications
You must be signed in to change notification settings - Fork 3.9k
[bug]: Issue attachment upload returns 400 for files with empty or unrecognized MIME types (.md, .yaml, .log, etc.) #8847
Description
Is there an existing issue for this?
- I have searched the existing issues
Current behavior
When uploading issue attachments via the Plane UI, certain file types (e.g., .md, .yaml, .yml, .log, .docx) fail with HTTP 400 "Invalid file type" even though they are perfectly valid files.
Root cause: The browser's File.type property returns an empty string for file extensions that don't have a well-known MIME type mapping in the browser's internal registry. The frontend sends this empty string as the type field in the POST request body.
In IssueAttachmentV2Endpoint.post() (file plane/app/views/issue/attachment.py), the validation at line ~100 is:
type = request.data.get("type", False)
# ...
if not type or type not in settings.ATTACHMENT_MIME_TYPES:
return Response(
{"error": "Invalid file type.", "status": False},
status=status.HTTP_400_BAD_REQUEST,
)When type is an empty string "", not type evaluates to True in Python (empty string is falsy), so the request is immediately rejected — regardless of the file extension or actual content.
Additionally, even when the browser does provide a MIME type (e.g., text/markdown for .md files on some systems), this type is not included in settings.ATTACHMENT_MIME_TYPES, causing the same 400 error.
Expected behavior
File attachments with common extensions like .md, .yaml, .log, .docx should upload successfully. If the browser doesn't provide a MIME type, the backend should infer it from the filename extension.
Steps to reproduce
- Open any issue in Plane (self-hosted v1.2.3)
- Click "Add Attachment"
- Select a
.mdfile (e.g.,README.md) - Upload fails with 400 error in the network tab:
{"error": "Invalid file type.", "status": false}
This also affects .yaml, .yml, .log, and other extensions where the browser returns an empty MIME type.
Suggested fix
In plane/app/views/issue/attachment.py, add MIME type inference from the filename when the browser-provided type is empty or not in the allowlist:
name = request.data.get("name")
type = request.data.get("type", False)
size = int(request.data.get("size", settings.FILE_SIZE_LIMIT))
# Infer MIME type from filename when browser sends empty or unrecognized type
if (not type or type not in settings.ATTACHMENT_MIME_TYPES) and name:
import mimetypes
guessed = mimetypes.guess_type(name)[0]
if guessed and guessed in settings.ATTACHMENT_MIME_TYPES:
type = guessed
elif guessed and guessed.startswith("text/"):
type = "text/plain" # Safe fallback for text-based files
else:
type = "application/octet-stream" # Generic binary fallback
if not type or type not in settings.ATTACHMENT_MIME_TYPES:
return Response(
{"error": "Invalid file type.", "status": False},
status=status.HTTP_400_BAD_REQUEST,
)This approach:
- Uses Python's
mimetypesmodule (stdlib, no dependencies) to infer the type from the filename - Maps recognized-but-not-allowlisted text types (like
text/markdown) totext/plain - Falls back to
application/octet-streamfor completely unknown types - Both
text/plainandapplication/octet-streamare already inATTACHMENT_MIME_TYPES - Does not weaken security — the allowlist check still runs after inference
Version
v1.2.3 (self-hosted, Docker)
Browser & OS
Chrome 146, Linux (also reproduced on Windows)