{"record":{"id":"0c3a64aeee6442db","repo":"discourse/discourse","slug":"all-parts-must-have-an-etag-and-a-valid-part-numbe","errorCode":null,"errorMessage":"All parts must have an etag and a valid part number","messagePattern":"All parts must have an etag and a valid part number","errorType":"exception","errorClass":"Discourse::InvalidParameters","httpStatus":400,"severity":"error","filePath":"lib/external_upload_helpers.rb","lineNumber":246,"sourceCode":"    ).performed!\n\n    external_upload_stub =\n      ExternalUploadStub.find_by(unique_identifier: unique_identifier, created_by: current_user)\n    return render_404 if external_upload_stub.blank?\n\n    message = check_multipart_upload_exists(external_upload_stub)\n    return render_404(message) if message.present?\n\n    store = multipart_store(external_upload_stub.upload_type)\n    parts =\n      parts\n        .map do |part|\n          part_number = part[:part_number]\n          etag = part[:etag]\n          part_number = validate_part_number(part_number)\n\n          if etag.blank?\n            raise Discourse::InvalidParameters.new(\n                    \"All parts must have an etag and a valid part number\",\n                  )\n          end\n\n          # this is done so it's an array of hashes rather than an array of\n          # ActionController::Parameters\n          { part_number: part_number, etag: etag }\n        end\n        .sort_by { |part| part[:part_number] }\n\n    begin\n      store.complete_multipart(\n        upload_id: external_upload_stub.external_upload_identifier,\n        key: external_upload_stub.key,\n        parts: parts,\n      )\n    rescue Aws::S3::Errors::ServiceError => err\n      return(","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/discourse/discourse/blob/1b2d7253e854205d2c95c80b2c6a1cdd42e45059/lib/external_upload_helpers.rb#L228-L264","documentation":"Error \"All parts must have an etag and a valid part number\" thrown in discourse/discourse.","triggerScenarios":"Thrown at lib/external_upload_helpers.rb:246 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":[],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"1b2d7253e854205d2c95c80b2c6a1cdd42e45059","analyzedAt":"2026-08-26T03:11:08.302Z","schemaVersion":2},"datasetVersion":"2026-08-26T07:17:17.940Z"}