Is there an existing issue for this?
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
.md file (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
mimetypes module (stdlib, no dependencies) to infer the type from the filename
- Maps recognized-but-not-allowlisted text types (like
text/markdown) to text/plain
- Falls back to
application/octet-stream for completely unknown types
- Both
text/plain and application/octet-stream are already in ATTACHMENT_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)
Is there an existing issue for this?
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.typeproperty 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 thetypefield in the POST request body.In
IssueAttachmentV2Endpoint.post()(fileplane/app/views/issue/attachment.py), the validation at line ~100 is:When
typeis an empty string"",not typeevaluates toTruein 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/markdownfor.mdfiles on some systems), this type is not included insettings.ATTACHMENT_MIME_TYPES, causing the same 400 error.Expected behavior
File attachments with common extensions like
.md,.yaml,.log,.docxshould upload successfully. If the browser doesn't provide a MIME type, the backend should infer it from the filename extension.Steps to reproduce
.mdfile (e.g.,README.md){"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:This approach:
mimetypesmodule (stdlib, no dependencies) to infer the type from the filenametext/markdown) totext/plainapplication/octet-streamfor completely unknown typestext/plainandapplication/octet-streamare already inATTACHMENT_MIME_TYPESVersion
v1.2.3 (self-hosted, Docker)
Browser & OS
Chrome 146, Linux (also reproduced on Windows)