puppetlabs/puppet · error · ArgumentError

Unable to parse ' ' using any of the formats

Error message

Unable to parse '%{str}' using any of the formats %{formats}

What it means

Timestamp.parse with an Array of formats (or :default, which expands to the DEFAULT_FORMATS array) tries each format via DateTime._strptime; a candidate is discarded when it returns nil, leaves :leftover (trailing unparsed text), or - when an explicit timezone argument was given - the parsed hash contains :zone. If every candidate is exhausted, ArgumentError 'Unable to parse ... using any of the formats ...' lists the joined formats.

Solutions

  1. Pass your own Array of formats covering the real shapes: Timestamp.parse(str, ['%d/%m/%Y %T', '%m/%d/%Y %T'])
  2. Normalize the string first - gsub('/', '-'), strip trailing zone names or whitespace
  3. If you supply a timezone argument, drop %Z/%z from the candidate formats (the :zone rejection rule)
  4. Pre-validate with a cheap regex per accepted shape before calling parse

Example fix

// before
ts = Puppet::Pops::Time::Timestamp.parse(api_date)   # '2023/01/31 12:00:00' -> raise listing defaults

// after
ts = Puppet::Pops::Time::Timestamp.parse(
  api_date.gsub('/', '-'),
  ['%F %T', '%FT%T', '%F %T.%N', '%F']
)
Defensive patterns

Strategy: try-catch

Validate before calling

SHAPES = [/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?\z/, /\A\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?\z/]
raise DataError, "unrecognized timestamp shape" unless SHAPES.any? { |r| str.match?(r) }

Try / catch

begin
  ts = Timestamp.parse(str, formats)
rescue ArgumentError => e
  raise DataError, "input #{str.inspect} matches none of #{formats.join(', ')}"
end

Prevention

When it happens

Trigger: Timestamp.parse('2023-13-45T99:99') against defaults (out-of-range fields), '2023/01/31' with slash separators against %F dash formats, '2023-01-31 12:00 hello' (leftover), or a zone-bearing string plus an explicit timezone argument (each candidate rejected via the :zone rule).

Common situations: Feeding log lines, database dumps, or third-party API timestamps with unexpected separators or precision into Timestamp()/Timestamp.parse; DST-ambiguous strings; inputs with trailing timezone names while a timezone arg was also supplied.

Understand the failure class

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/0f6c3221a1e82380. Report an issue: GitHub.

Appendix: source

Thrown at lib/puppet/pops/time/timestamp.rb:87

    has_timezone = !(timezone.nil? || timezone.empty? || timezone == :default)
    if format.nil? || format == :default
      format = has_timezone ? DEFAULT_FORMATS_WO_TZ : DEFAULT_FORMATS
    end

    parsed = nil
    if format.is_a?(Array)
      format.each do |fmt|
        parsed = DateTime._strptime(str, fmt)
        next if parsed.nil?

        if parsed.include?(:leftover) || (has_timezone && parsed.include?(:zone))
          parsed = nil
          next
        end
        break
      end
      if parsed.nil?
        raise ArgumentError, _(
          "Unable to parse '%{str}' using any of the formats %{formats}"
        ) % { str: str, formats: format.join(', ') }
      end
    else
      parsed = DateTime._strptime(str, format)
      if parsed.nil? || parsed.include?(:leftover)
        raise ArgumentError, _("Unable to parse '%{str}' using format '%{format}'") % { str: str, format: format }
      end

      if has_timezone && parsed.include?(:zone)
        raise ArgumentError, _(
          'Using a Timezone designator in format specification is mutually exclusive to providing an explicit timezone argument'
        )
      end
    end
    unless has_timezone
      timezone = parsed[:zone]
      has_timezone = !timezone.nil?

View on GitHub (pinned to e227c27540)