{"record":{"id":"984410e130fde9a3","repo":"docusealco/docuseal","slug":"file-param-is-missing","errorCode":null,"errorMessage":"file param is missing","messagePattern":"file param is missing","errorType":"validation","errorClass":"Submitters::ParamsError","httpStatus":null,"severity":"error","filePath":"lib/submitters.rb","lineNumber":127,"sourceCode":"    if AccountConfig.exists?(account_id: submitter.account_id,\n                             key: AccountConfig::COMBINE_PDF_RESULT_KEY,\n                             value: true) &&\n       submitter.submission.completed_at? &&\n       submitter.submission.template_fields.none? { |f| f['type'] == 'verification' }\n      return [submitter.submission.combined_document_attachment || Submissions::EnsureCombinedGenerated.call(submitter)]\n    end\n\n    original_documents = submitter.submission.schema_documents.preload(:blob)\n    is_more_than_two_images = original_documents.many?(&:image?)\n\n    submitter.documents.preload(:blob).reject do |attachment|\n      is_more_than_two_images &&\n        original_documents.find { |a| a.uuid == (attachment.metadata['original_uuid'] || attachment.uuid) }&.image?\n    end\n  end\n\n  def create_attachment!(submitter, file, metadata: {})\n    raise ParamsError, 'file param is missing' if file.blank?\n\n    extension = File.extname(file.original_filename).delete_prefix('.').downcase\n\n    if DANGEROUS_EXTENSIONS.include?(extension)\n      raise MaliciousFileExtension, \"File type '.#{extension}' is not allowed.\"\n    end\n\n    blob = ActiveStorage::Blob.create_and_upload!(io: file.tap(&:rewind).open,\n                                                  filename: file.original_filename,\n                                                  content_type: file.content_type,\n                                                  metadata:)\n\n    ActiveStorage::Attachment.create!(blob:, name: 'attachments', record: submitter)\n  end\n\n  def normalize_preferences(account, user, params)\n    preferences = {}\n","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/docusealco/docuseal/blob/004a22c1c88109c7ba0b567df011a8cb13894001/lib/submitters.rb#L109-L145","documentation":"Submitters.create_attachment! (lib/submitters.rb:127) raises ParamsError 'file param is missing' when the uploaded file argument is blank before it ever touches storage. It is the guard for submitter attachment upload endpoints (e.g. adding documents/images to a submitter): the multipart 'file' field must be present and non-empty.","triggerScenarios":"POST to the submitter attachments endpoint as JSON instead of multipart/form-data so params[:file] is a string/absent; multipart body missing the file field or using a different field name; an empty file part (0-byte with blank Rack object); calling create_attachment! internally with nil.","commonSituations":"Frontends sending fetch with Content-Type: application/json instead of FormData; curl posts without -F; reverse proxies or body-size limits stripping large parts; field named 'document' or 'files' instead of the expected param.","solutions":["Send the request as multipart/form-data with the exact file field name the endpoint expects (Rack yields an ActionDispatch::Http::UploadedFile).","Client-side, assert a file is selected before submitting and disable the upload button otherwise.","If using curl: curl -F 'file=@doc.pdf' (not -d).","Rescue Submitters::ParamsError at the controller boundary and map it to a 400 with this message."],"exampleFix":"# before (JSON body — file param never materializes)\nfetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) })\n\n# after\nconst form = new FormData()\nform.append('file', fileInput.files[0])\nfetch(url, { method: 'POST', body: form })","handlingStrategy":"validation","validationCode":"# Validate the upload before calling create_attachment!\ndef upload_file?(param)\n  param.is_a?(ActionDispatch::Http::UploadedFile) && param.present? &&\n    param.original_filename.present?\nend","typeGuard":null,"tryCatchPattern":"begin\n  Submitters.create_attachment!(submitter, params[:file])\nrescue Submitters::ParamsError => e\n  render json: { error: e.message }, status: :bad_request\nend","preventionTips":["Send multipart/form-data (FormData / curl -F), never a JSON body, for file uploads.","Use the exact file field name the endpoint documents.","Disable submit until a file is chosen client-side.","Map ParamsError to 400 at the controller boundary."],"tags":["docuseal","file-upload","multipart","params-validation"],"backgroundTag":"missing-file-upload","analyzedSha":"004a22c1c88109c7ba0b567df011a8cb13894001","analyzedAt":"2026-08-21T13:38:23.343Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}