{"record":{"id":"008c4e2bbead98e1","repo":"we-promise/sure","slug":"invalid-file-type","errorCode":"invalid_file_type","errorMessage":"Invalid file type. Please upload a CSV file.","messagePattern":"Invalid file type\\. Please upload a CSV file\\.","errorType":"http","errorClass":"Import::Preflight::PreflightError","httpStatus":422,"severity":"error","filePath":"app/models/import/preflight.rb","lineNumber":395,"sourceCode":"        payload: {\n          error: \"content_too_large\",\n          message: \"Content is too large. Maximum size is #{SureImport.max_ndjson_size / 1.megabyte}MB.\"\n        }\n      )\n    end\n\n    def invalid_sure_file_type_response\n      Response.new(\n        status: :unprocessable_entity,\n        payload: {\n          error: \"invalid_file_type\",\n          message: \"Invalid file type. Please upload a Sure NDJSON file.\"\n        }\n      )\n    end\n\n    def raise_response(response)\n      raise PreflightError, response\n    end\n\n    def unsupported_import_type_response\n      Response.new(\n        status: :unprocessable_entity,\n        payload: {\n          error: \"unsupported_import_type\",\n          message: \"Preflight supports CSV import types and SureImport.\"\n        }\n      )\n    end\nend\n","sourceCodeStart":377,"sourceCodeEnd":408,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/import/preflight.rb#L377-L408","documentation":"Import::Preflight#csv_file_upload_attributes (app/models/import/preflight.rb:190) returns HTTP 422 {error: 'invalid_file_type'} with message 'Invalid file type. Please upload a CSV file.' when the multipart part's content_type is not in Import::ALLOWED_CSV_MIME_TYPES = [text/csv, text/plain, application/vnd.ms-excel, application/csv] (app/models/import.rb:37). Unlike the NDJSON path there is no filename-extension fallback: only the declared part Content-Type is inspected, and the same check runs at import creation (app/controllers/api/v1/imports_controller.rb:87).","triggerScenarios":"curl -F 'file=@export.csv' (the part defaults to application/octet-stream); uploading .xlsx (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet is not allowlisted, only legacy vnd.ms-excel); a .tsv sent as text/tab-separated-values; a JSON file sent to the CSV path.","commonSituations":"Scripts using curl, Python requests, or Faraday that never set an explicit part content type; Excel's 'Export as .xlsx' instead of 'CSV UTF-8'; Linux tools that sniff and send unusual MIME types.","solutions":["Declare the part type explicitly: curl -F 'file=@export.csv;type=text/csv'","Convert .xlsx/.tsv to CSV UTF-8 before uploading","Renaming the file does not help on the CSV path — the part Content-Type must match the allowlist","If the client cannot set part content types, send raw_file_content instead; that path skips the MIME check and only checks size"],"exampleFix":"# before\ncurl -F 'file=@export.csv' https://app/api/v1/imports\n# → 422 invalid_file_type (part sent as application/octet-stream)\n\n# after\ncurl -F 'file=@export.csv;type=text/csv' https://app/api/v1/imports","handlingStrategy":"validation","validationCode":"ALLOWED_CSV_TYPES = %w[text/csv text/plain application/vnd.ms-excel application/csv]\npart = Faraday::FilePart.new(io, 'text/csv', 'import.csv') # never rely on client-default octet-stream\nraise 'part type not allowed' unless ALLOWED_CSV_TYPES.include?('text/csv')","typeGuard":"def csv_part_allowed?(content_type)\n  %w[text/csv text/plain application/vnd.ms-excel application/csv].include?(content_type.to_s)\nend","tryCatchPattern":null,"preventionTips":["Always set the multipart part type explicitly (curl: 'file=@f.csv;type=text/csv')","Convert .xlsx/.tsv to CSV UTF-8 before upload — renaming alone does nothing","If your client cannot set part types, use raw_file_content, which skips the MIME check"],"tags":["rails","import","csv","file-upload","mime-type","http-422"],"backgroundTag":"unsupported-media-type","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}