{"record":{"id":"e158e3a8afd97718","repo":"we-promise/sure","slug":"import-maxrowcountexceedederror","errorCode":null,"errorMessage":"Import::MaxRowCountExceededError","messagePattern":"Import::MaxRowCountExceededError","errorType":"exception","errorClass":"Import::MaxRowCountExceededError","httpStatus":null,"severity":"error","filePath":"app/models/import.rb","lineNumber":276,"sourceCode":"\n  def publish\n    # A redelivered or stray ImportJob must not re-import data that already\n    # committed (types without row dedup would double-apply), and must not\n    # race a revert that owns the record. A failed import is deliberately NOT\n    # blocked: its transaction rolled back, so a re-run is a safe retry.\n    if complete? || reverting? || revert_failed?\n      DebugLogEntry.capture(\n        category: \"background_jobs\",\n        level: \"warn\",\n        message: \"Import publish skipped: job redelivered while record was #{status}\",\n        source: self.class.name,\n        family: family,\n        metadata: { record_type: type, record_id: id, status: status }\n      )\n      return\n    end\n\n    raise MaxRowCountExceededError if row_count_exceeded?\n\n    import!\n\n    family.sync_later\n\n    update! status: :complete\n  rescue => error\n    update! status: :failed, error: error.message\n  end\n\n  def revert_later\n    raise \"Import is not revertable\" unless revertable?\n\n    update! status: :reverting\n\n    RevertImportJob.perform_later(self)\n  end\n","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/import.rb#L258-L294","documentation":"The same row-count guard re-checked inside the job-side publish path: it raises MaxRowCountExceededError when row_count_exceeded? holds at execution time — defense in depth if rows grew or enqueue bypassed publish_later. Unlike publish_later, this runs inside a rescue that writes status :failed with error 'Import::MaxRowCountExceededError' onto the import record.","triggerScenarios":"ImportJob executing an import whose rows_count exceeds max_row_count at run time — rows appended after publish_later, a condition that appeared between upload and publish, or code enqueuing ImportJob directly without the publish_later guard.","commonSituations":"Rows added to the import record post-upload; job retries after data changed; custom code paths calling publish!/ImportJob directly.","solutions":["Inspect the import record: status is :failed with error 'Import::MaxRowCountExceededError'; row data is intact for re-splitting","Reduce rows below max_row_count (delete excess rows or split into a new import) then publish again","Always enqueue through publish_later so the guard fires before the job runs"],"exampleFix":"// before\nImportJob.perform_later(import) # bypasses the pre-enqueue guard\n\n// after\nimport.publish_later # guarded: raises Import::MaxRowCountExceededError before enqueueing","handlingStrategy":"validation","validationCode":"import.rows_count <= import.max_row_count && !%w[complete reverting revert_failed].include?(import.status) # re-check at job time; the guard raises and the rescue records status :failed","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always enqueue through publish_later so the guard fires pre-enqueue","After a failed publish, trim rows below max_row_count and re-publish — the record's error field carries 'Import::MaxRowCountExceededError'","Monitor imports stuck in :failed with that error message as a row-limit funnel metric"],"tags":["import","row-limit","background-jobs","failed-status"],"backgroundTag":"row-limit-exceeded","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}