opf/openproject · error · Exports::PDF::Components::Gantt::InvalidDateRangeError

The selected work package date range exceeds the allowable P

Error message

The selected work package date range exceeds the allowable PDF export limit. Please condense the range to a maximum of %{years} years.

What it means

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.

Source

Thrown at app/models/exports/pdf/components/gantt/gantt_builder.rb:872

    end

    # Returns a helper object containing information about the line to be drawn
    # @param [WorkPackage] work_package
    # @param [Array<GanttDataPageGroup>] page_groups
    def collect_line_infos(work_package, page_groups)
      rows = collect_rows_by_work_package(work_package, page_groups)
      start, finish = collect_start_and_finish_rows(rows)
      GanttDataLineInfo.new(rows[0].page.group, rows, start, finish)
    end

    # Builds the dates range for the given work packages
    # @param [Array<WorkPackage>] work_packages
    # @return [Array<Date>]
    def collect_column_dates(work_packages)
      wp_dates = collect_work_packages_dates(work_packages)
      years = ((wp_dates.last - wp_dates.first) / 365).floor
      if years > MAX_YEAR_RANGE
        raise InvalidDateRangeError, I18n.t(:error_pdf_date_range_too_long, years: MAX_YEAR_RANGE)
      end

      build_column_dates_range(wp_dates.first..wp_dates.last)
    end

    # Collects the unique dates of the given work packages (start and/or due date)
    # @param [Array<WorkPackage>] work_packages
    # @return [Array<Date>]
    def collect_work_packages_dates(work_packages)
      work_packages.map do |work_package|
        [work_package.start_date || work_package.due_date, work_package.due_date || work_package.start_date]
      end.flatten.uniq.sort
    end

    # Collects all rows for the given work package
    # @param [WorkPackage] work_package
    # @param [Array<GanttDataPageGroup>] page_groups
    # @return [Array<GanttDataRow>]

View on GitHub (pinned to d9742c43f3)

Solutions

  1. Narrow the exported set: filter by date range or deselect the extreme work packages before exporting.
  2. 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).
  3. If the long range is legitimate, split the export into several smaller date windows.

Example fix

# before
scope = project.work_packages
Exports::Pdf::Components::Gantt::GanttBuilder.new(...).build(scope)

# after (clamp the exported set to a sane window)
scope = project.work_packages.where('due_date <= ?', 3.years.from_now)
                              .where('COALESCE(start_date, due_date) >= ?', 1.year.ago)
Defensive patterns

Strategy: validation

Validate before calling

dates = work_packages.flat_map { |wp| [wp.start_date, wp.due_date] }.compact
years = ((dates.max - dates.min).to_i / 365)
raise ArgumentError, 'range too long' if years > MAX_YEAR_RANGE

Try / catch

begin
  builder.build(work_packages)
rescue Exports::Pdf::Components::Gantt::GanttBuilder::InvalidDateRangeError
  render_error I18n.t(:error_pdf_date_range_too_long, years: MAX_YEAR_RANGE)
end

Prevention

When it happens

Trigger: 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.

Common situations: 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.


AI-assisted analysis of opf/openproject@d9742c43f3 (2026-08-21). Data as JSON: /api/errors/362353f46abe0e84. Report an issue: GitHub.