puppetlabs/puppet · error · ArgumentError

The argument 'file' must be a String, got %{type}

Error message

The argument 'file' must be a String, got %{type}

What it means

Compiler#parse_file requires the file argument to be a String path, even though the doc comment mentions Path. Passing a Pathname (very common in Ruby tooling) or an IO object raises ArgumentError naming the actual class. The path is handed straight to the parser, which expects a String.

Source

Thrown at lib/puppet/pal/compiler.rb:158

    # @return [Puppet::Pops::Model::Program] returns a `Program` instance on success
    #
    def parse_string(code_string, source_file = nil)
      unless code_string.is_a?(String)
        raise ArgumentError, _("The argument 'code_string' must be a String, got %{type}") % { type: code_string.class }
      end

      internal_evaluator.parse_string(code_string, source_file)
    end

    # Parses and validates a puppet language file and returns an instance of Puppet::Pops::Model::Program on success.
    # If the content is not valid an error is raised.
    #
    # @param file [String] a file with puppet language content to parse and validate
    # @return [Puppet::Pops::Model::Program] returns a `Program` instance on success
    #
    def parse_file(file)
      unless file.is_a?(String)
        raise ArgumentError, _("The argument 'file' must be a String, got %{type}") % { type: file.class }
      end

      internal_evaluator.parse_file(file)
    end

    # Parses a puppet data type given in String format and returns that type, or raises an error.
    # A type is needed in calls to `new` to create an instance of the data type, or to perform type checking
    # of values - typically using `type.instance?(obj)` to check if `obj` is an instance of the type.
    #
    # @example Verify if obj is an instance of a data type
    #   # evaluates to true
    #   pal.type('Enum[red, blue]').instance?("blue")
    #
    # @example Create an instance of a data type
    #   # using an already create type
    #   t = pal.type('Car')
    #   pal.create(t, 'color' => 'black', 'make' => 't-ford')
    #

View on GitHub (pinned to e227c27540)

Solutions

  1. Convert explicitly: parse_file(path.to_s)
  2. Standardize on String paths at the PAL boundary in your wrapper code
  3. If you hold an IO object, close it and pass the on-disk path instead

Example fix

# before
compiler.parse_file(Pathname.new('manifests/site.pp'))

# after
compiler.parse_file(Pathname.new('manifests/site.pp').to_s)
Defensive patterns

Strategy: type-guard

Type guard

def string_path?(value)
  value.is_a?(String) && !value.empty?
end

raise ArgumentError, 'file must be a String path' unless string_path?(file)

Prevention

When it happens

Trigger: parse_file(Pathname.new('manifests/site.pp')) after using Pathname/Dir tooling; parse_file(File.open('site.pp')) passing the handle instead of the path; any code path where the path variable was built from Pathname operations.

Common situations: Tooling that uses Pathname throughout; confusion caused by the documented [Path, String] type versus the String-only implementation; wrapping PAL in apps that model paths as objects.

Related errors


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