puppetlabs/puppet · error · Puppet::Util::Windows::Error

Failed to call GetLongPathName

Error message

Failed to call GetLongPathName

What it means

Puppet::Util::Windows::File.get_long_pathname expands a path to its long form via GetLongPathNameW: a first call sizes the buffer, a second converts, and failure of the second call raises Puppet::Util::Windows::Error. GetLongPathNameW only succeeds when every component of the path actually exists - a nonexistent path is the leading cause (code 2/3), with access-denied on intermediate directories next.

Source

Thrown at lib/puppet/util/windows/file.rb:257

  def readlink(link_name)
    link = nil
    open_symlink(link_name) do |handle|
      link = resolve_symlink(handle)
    end

    link
  end
  module_function :readlink

  def get_long_pathname(path)
    converted = ''.dup
    FFI::Pointer.from_string_to_wide_string(path) do |path_ptr|
      # includes terminating NULL
      buffer_size = GetLongPathNameW(path_ptr, FFI::Pointer::NULL, 0)
      FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr|
        if GetLongPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE
          raise Puppet::Util::Windows::Error, _("Failed to call GetLongPathName")
        end

        converted = converted_ptr.read_wide_string(buffer_size - 1)
      end
    end

    converted
  end
  module_function :get_long_pathname

  def get_short_pathname(path)
    converted = ''.dup
    FFI::Pointer.from_string_to_wide_string(path) do |path_ptr|
      # includes terminating NULL
      buffer_size = GetShortPathNameW(path_ptr, FFI::Pointer::NULL, 0)
      FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr|
        if GetShortPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE
          raise Puppet::Util::Windows::Error, "Failed to call GetShortPathName"

View on GitHub (pinned to e227c27540)

Solutions

  1. Verify File.exist?(path) before converting - GetLongPathName requires an existing path
  2. Map e.code: 2/3 missing component, 5 traversal denied, 53/1231 network share unreachable
  3. Create the target directory tree first, then convert
  4. Fall back to the original string when expansion is only cosmetic

Example fix

// before
long = Puppet::Util::Windows::File.get_long_pathname(short_path)  # raises if missing

// after
long = if File.exist?(short_path)
         Puppet::Util::Windows::File.get_long_pathname(short_path)
       else
         short_path
       end
Defensive patterns

Strategy: validation

Validate before calling

raise ArgumentError, "#{path} must exist for long-path conversion" unless File.exist?(path)
long = Puppet::Util::Windows::File.get_long_pathname(path)

Try / catch

begin
  long = Puppet::Util::Windows::File.get_long_pathname(path)
rescue Puppet::Util::Windows::Error => e
  raise if e.code == 5  # access denied is a real problem
  long = path           # 2/3: component missing - keep original
end

Prevention

When it happens

Trigger: get_long_pathname(path) where path (or any parent) does not currently exist; the path is a network share whose server is unreachable; a parent directory denies traversal (5); the path is already long-form but contains wildcard/invalid characters.

Common situations: Expanding 8.3 short names (e.g. PROGRA~1, from legacy installers or ENV['TEMP']) for directories created later in the run; converting paths captured before a package uninstall removed them; concurrent deletion racing the conversion.

Related errors


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