faker-ruby/faker · error · ArgumentError

Invalid birthday: #{birthday}. Danish CPR numbers are only d

Error message

Invalid birthday: #{birthday}. Danish CPR numbers are only distributed to persons born between 1858 and 2057.

What it means

Raised by the private danish_control_digits helper in Faker::IdNumber.danish_id_number when the birthday's century is 18xx but the two-digit year is below 58. The Danish CPR sequence-number scheme only encodes birth years from 1858 onward (century digit 5/6/7/8 with year digits >= 58), so a date in 1800-1857 has no valid control digit and the method raises ArgumentError instead of generating an invalid number.

Source

Thrown at lib/faker/default/id_number.rb:393

        subtraction = 11 - remainder.to_i
        digits = { 10 => 'X', 11 => '0' }
        digits.include?(subtraction) ? digits[subtraction] : subtraction.to_s
      end

      def danish_control_digits(birthday)
        year = birthday.year
        century = year.to_s.slice(0, 2).to_i
        year_digits = year.to_s.slice(2, 2).to_i
        error_message = "Invalid birthday: #{birthday}. Danish CPR numbers are only distributed to persons born between 1858 and 2057."

        case century
        when 18
          # If 5, 6, 7 or 8 and the year numbers are greater than or equal to 58, you were born in 18XX.
          case year_digits
          when 58..99
            [5, 6, 7, 8]
          else
            raise ArgumentError, error_message
          end
        when 19
          # If 0, 1, 2 or 3, you are always born in 19XX.
          # If 4 or 9, you are born in 19XX if the year digits are greater than 36.

          case year_digits
          when 0..36
            [0, 1, 2, 3]
          else # 37..99
            [0, 1, 2, 3, 4, 9]
          end
        else
          # If 4, 5, 6, 7, 8 or 9 and the year digits are less than or equal to 36, you were born in 20XX.
          # 5, 6, 7 and 8 are not distributed to persons, with year digits from and including 37 to and including 57.
          case year_digits
          when 0..36
            [4, 5, 6, 7, 8, 9]
          when 37..57

View on GitHub (pinned to cca4184947)

Solutions

  1. Use a birthday between 1858-01-01 and 2057-12-31, e.g. Date.new(1890, 5, 3).
  2. Clamp or validate user-supplied birthdates before passing them: raise or substitute a default when the year is outside 1858..2057.
  3. If you truly need IDs for pre-1858 persons, CPR cannot represent them; generate a plain numeric identifier instead of a CPR number.

Example fix

# before
Faker::IdNumber.danish_id_number(birthday: Date.new(1850, 1, 1)) # ArgumentError

# after
Faker::IdNumber.danish_id_number(birthday: Date.new(1859, 1, 1))
Defensive patterns

Strategy: validation

Validate before calling

def cpr_compatible_birthday?(date)
  date.year.between?(1858, 2057)
end

birthday = Date.new(1990, 3, 5) if !cpr_compatible_birthday?(user_birthday)
Faker::IdNumber.danish_id_number(birthday: birthday)

Type guard

def cpr_compatible_birthday?(date)
  date.is_a?(Date) && date.year.between?(1858, 2057)
end

Try / catch

begin
  Faker::IdNumber.danish_id_number(birthday: birthday)
rescue ArgumentError
  Faker::IdNumber.danish_id_number(birthday: Faker::Date.birthday) # fall back to default range
end

Prevention

When it happens

Trigger: Faker::IdNumber.danish_id_number(birthday: Date.new(1812, 5, 3)) or any birthday between 1800-01-01 and 1857-12-31: century == 18 and year_digits falls outside 58..99, hitting the raise at lib/faker/default/id_number.rb:393.

Common situations: Seeding historical test data with very old birthdates; passing Date.parse of free-text user input that contains a mistyped year (e.g. 1050 or 1850 instead of 1950); factories that randomize birthdays over centuries (Faker::Date.birthday defaults to a recent range, so this only occurs with explicit dates).

Related errors


AI-assisted analysis of faker-ruby/faker@cca4184947 (2026-08-21). Data as JSON: /api/errors/8b93de2761dc0b53. Report an issue: GitHub.