{"record":{"id":"362353f46abe0e84","repo":"opf/openproject","slug":"the-selected-work-package-date-range-exceeds-the-a","errorCode":null,"errorMessage":"The selected work package date range exceeds the allowable PDF export limit. Please condense the range to a maximum of %{years} years.","messagePattern":"The selected work package date range exceeds the allowable PDF export limit\\. Please condense the range to a maximum of %(.+?) years\\.","errorType":"exception","errorClass":"Exports::PDF::Components::Gantt::InvalidDateRangeError","httpStatus":null,"severity":"error","filePath":"app/models/exports/pdf/components/gantt/gantt_builder.rb","lineNumber":872,"sourceCode":"    end\n\n    # Returns a helper object containing information about the line to be drawn\n    # @param [WorkPackage] work_package\n    # @param [Array<GanttDataPageGroup>] page_groups\n    def collect_line_infos(work_package, page_groups)\n      rows = collect_rows_by_work_package(work_package, page_groups)\n      start, finish = collect_start_and_finish_rows(rows)\n      GanttDataLineInfo.new(rows[0].page.group, rows, start, finish)\n    end\n\n    # Builds the dates range for the given work packages\n    # @param [Array<WorkPackage>] work_packages\n    # @return [Array<Date>]\n    def collect_column_dates(work_packages)\n      wp_dates = collect_work_packages_dates(work_packages)\n      years = ((wp_dates.last - wp_dates.first) / 365).floor\n      if years > MAX_YEAR_RANGE\n        raise InvalidDateRangeError, I18n.t(:error_pdf_date_range_too_long, years: MAX_YEAR_RANGE)\n      end\n\n      build_column_dates_range(wp_dates.first..wp_dates.last)\n    end\n\n    # Collects the unique dates of the given work packages (start and/or due date)\n    # @param [Array<WorkPackage>] work_packages\n    # @return [Array<Date>]\n    def collect_work_packages_dates(work_packages)\n      work_packages.map do |work_package|\n        [work_package.start_date || work_package.due_date, work_package.due_date || work_package.start_date]\n      end.flatten.uniq.sort\n    end\n\n    # Collects all rows for the given work package\n    # @param [WorkPackage] work_package\n    # @param [Array<GanttDataPageGroup>] page_groups\n    # @return [Array<GanttDataRow>]","sourceCodeStart":854,"sourceCodeEnd":890,"githubUrl":"https://github.com/opf/openproject/blob/d9742c43f3424c34b63550f8c03f201fe5c3040c/app/models/exports/pdf/components/gantt/gantt_builder.rb#L854-L890","documentation":"The Gantt PDF builder (Exports::Pdf::Components::Gantt::GanttBuilder#collect_column_dates) measures the span from the earliest to the latest work package date, computes whole years, and raises InvalidDateRangeError with error_pdf_date_range_too_long when it exceeds the MAX_YEAR_RANGE constant. The cap keeps the PDF from generating an unbounded number of date columns.","triggerScenarios":"Exporting work packages to a Gantt PDF where any included work package's start/due dates stretch the overall range past MAX_YEAR_RANGE years — e.g. a milestone due 2099, a task mistakenly dated 1900, or genuinely decades-long plans.","commonSituations":"Typos in dates (wrong century/year, 1994 instead of 2024); imported data with placeholder far-future dates; exporting a filtered set that happens to include one extreme-dated work package.","solutions":["Narrow the exported set: filter by date range or deselect the extreme work packages before exporting.","Fix the outlier dates — inspect the earliest and latest work packages in the selection (the error follows from min start_date to max due_date).","If the long range is legitimate, split the export into several smaller date windows."],"exampleFix":"# before\nscope = project.work_packages\nExports::Pdf::Components::Gantt::GanttBuilder.new(...).build(scope)\n\n# after (clamp the exported set to a sane window)\nscope = project.work_packages.where('due_date <= ?', 3.years.from_now)\n                              .where('COALESCE(start_date, due_date) >= ?', 1.year.ago)","handlingStrategy":"validation","validationCode":"dates = work_packages.flat_map { |wp| [wp.start_date, wp.due_date] }.compact\nyears = ((dates.max - dates.min).to_i / 365)\nraise ArgumentError, 'range too long' if years > MAX_YEAR_RANGE","typeGuard":null,"tryCatchPattern":"begin\n  builder.build(work_packages)\nrescue Exports::Pdf::Components::Gantt::GanttBuilder::InvalidDateRangeError\n  render_error I18n.t(:error_pdf_date_range_too_long, years: MAX_YEAR_RANGE)\nend","preventionTips":["Pre-check the min/max dates of the export selection and surface the span before the export job starts.","Guard data entry against century/year typos (validation on very old or far-future dates).","Offer the UI export with a date-window picker so users self-limit the range."],"tags":["pdf-export","gantt","date-range","export-limits"],"backgroundTag":"export-limit-exceeded","analyzedSha":"d9742c43f3424c34b63550f8c03f201fe5c3040c","analyzedAt":"2026-08-21T14:40:06.829Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}