puppetlabs/puppet · error · Puppet::Util::Windows::Error
DeviceIoControl(#{handle}, #{io_control_code}, #{in_buffer},
Error message
DeviceIoControl(#{handle}, #{io_control_code}, #{in_buffer}, #{in_buffer ? in_buffer.size : ''}, #{out_buffer}, #{out_buffer ? out_buffer.size : ''}) What it means
device_io_control raises Puppet::Util::Windows::Error when the DeviceIoControl Win32 call itself returns FALSE, echoing handle, control code, and buffer pointers/sizes into the message. The real reason is in e.code: for FSCTL_GET_REPARSE_POINT the classic values are ERROR_NOT_A_REPARSE_POINT (4390/0x1126) when the file has no reparse data, plus invalid-handle, access-denied, and insufficient-buffer variants.
Source
Thrown at lib/puppet/util/windows/file.rb:197
end
def self.device_io_control(handle, io_control_code, in_buffer = nil, out_buffer = nil)
if out_buffer.nil?
raise Puppet::Util::Windows::Error, _("out_buffer is required")
end
FFI::MemoryPointer.new(:dword, 1) do |bytes_returned_ptr|
result = DeviceIoControl(
handle,
io_control_code,
in_buffer, in_buffer.nil? ? 0 : in_buffer.size,
out_buffer, out_buffer.size,
bytes_returned_ptr,
nil
)
if result == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, "DeviceIoControl(#{handle}, #{io_control_code}, " \
"#{in_buffer}, #{in_buffer ? in_buffer.size : ''}, " \
"#{out_buffer}, #{out_buffer ? out_buffer.size : ''}"
end
end
out_buffer
end
def reparse_point?(file_name)
attributes = get_attributes(file_name, false)
return false if attributes == INVALID_FILE_ATTRIBUTES
(attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
end
module_function :reparse_point?
def symlink?(file_name)View on GitHub (pinned to e227c27540)
Solutions
- Gate on e.code: 4390 means 'not a reparse point' (skip, don't fail), 6 stale handle (reopen), 122 grow the buffer
- Check reparse_point?(file_name) before opening/issuing FSCTL_GET_REPARSE_POINT
- Open handles with FILE_FLAG_OPEN_REPARSE_POINT when inspecting links
- Allocate reparse out_buffers >= MAXIMUM_REPARSE_DATA_BUFFER_SIZE (10240)
Example fix
// before Puppet::Util::Windows::File.device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, out) # plain file -> 4390 // after if Puppet::Util::Windows::File.reparse_point?(path) Puppet::Util::Windows::File.device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, out) end
Defensive patterns
Strategy: try-catch
Validate before calling
raise ArgumentError, 'not a reparse point' unless Puppet::Util::Windows::File.reparse_point?(path)
Try / catch
begin Puppet::Util::Windows::File.device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, out_buffer) rescue Puppet::Util::Windows::Error => e raise unless e.code == 4390 # ERROR_NOT_A_REPARSE_POINT - benign probe miss nil end
Prevention
- Call reparse_point? before issuing FSCTL_GET_REPARSE_POINT
- Open target files with FILE_FLAG_OPEN_REPARSE_POINT
- Size out_buffer to at least MAXIMUM_REPARSE_DATA_BUFFER_SIZE (10240) to avoid code 122
When it happens
Trigger: Sending FSCTL_GET_REPARSE_POINT to a handle opened on a plain (non-reparse) file (4390); using a stale or closed handle (6); a handle opened without FILE_FLAG_OPEN_REPARSE_POINT so the filter never sees the request; an out_buffer smaller than the reparse data requires (122, ERROR_INSUFFICIENT_BUFFER).
Common situations: Symlink-inspection code that assumes every file is a reparse point after a racy existence check; handles kept across I/O boundaries and invalidated by filter drivers; buffers sized below the documented 10240-byte minimum for reparse data.
Related errors
- ReplaceFile(#{target}, #{source})
- MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})
- CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})
- GetFileAttributes(#{file_name})
- Failed to set file attributes
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/39020a2c0f817e85.
Report an issue: GitHub.