puppetlabs/puppet · error · Puppet::Util::Windows::Error
CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})
Error message
CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)}) What it means
Puppet::Util::Windows::File.symlink calls CreateSymbolicLinkW (flag 0x1 when the target is a directory, else 0x0) and raises Puppet::Util::Windows::Error on FALSE. On modern Windows the dominant cause is ERROR_PRIVILEGE_NOT_HELD (1314): creating symlinks requires admin elevation or Developer Mode. e.code disambiguates privilege problems from missing paths.
Source
Thrown at lib/puppet/util/windows/file.rb:54
def move_file_ex(source, target, flags = 0)
result = MoveFileExW(wide_string(source.to_s),
wide_string(target.to_s),
flags)
return true if result != FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, "MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})"
end
module_function :move_file_ex
def symlink(target, symlink)
flags = File.directory?(target) ? 0x1 : 0x0
result = CreateSymbolicLinkW(wide_string(symlink.to_s),
wide_string(target.to_s), flags)
return true if result != FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, "CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})"
end
module_function :symlink
def exist?(path)
path = path.to_str if path.respond_to?(:to_str) # support WatchedFile
path = path.to_s # support String and Pathname
seen_paths = []
# follow up to 64 symlinks before giving up
0.upto(64) do |_depth|
# return false if this path has been seen before. This is protection against circular symlinks
return false if seen_paths.include?(path.downcase)
result = get_attributes(path, false)
# return false for path not found
return false if result == INVALID_FILE_ATTRIBUTES
View on GitHub (pinned to e227c27540)
Solutions
- Run elevated, enable Windows Developer Mode, or grant SeCreateSymbolicLinkPrivilege via secedit/group policy (fixes code 1314)
- Verify the target exists before creating so the directory flag is computed correctly
- For directories, fall back to a junction (no privilege needed) when 1314 is raised
- Rescue and copy/link-file fallback when symlinks are not available in the environment
Example fix
// before
Puppet::Util::Windows::File.symlink(target, link) # non-elevated -> 1314 privilege not held
// after
begin
Puppet::Util::Windows::File.symlink(target, link)
rescue Puppet::Util::Windows::Error => e
raise unless e.code == 1314
# junctions need no privilege for local directories
Puppet::Util::Windows::File.symlink(target, link) if false
system("cmd /c mklink /J \"#{link}\" \"#{target}\"")
end Defensive patterns
Strategy: try-catch
Validate before calling
raise ArgumentError, 'symlink target must exist' unless File.exist?(target) # non-elevated callers will usually fail with 1314 regardless - probe privilege cheaply: admin = `whoami /groups | findstr /c:"S-1-16-12288"`.strip.length > 0
Try / catch
begin
Puppet::Util::Windows::File.symlink(target, link)
rescue Puppet::Util::Windows::Error => e
raise unless e.code == 1314 # ERROR_PRIVILEGE_NOT_HELD
system('cmd', '/c', 'mklink', '/J', link, target) if File.directory?(target) # junction fallback
end Prevention
- Run elevated or enable Developer Mode before creating symlinks
- Grant SeCreateSymbolicLinkPrivilege to service accounts via group policy
- Fall back to junctions for directories - they need no privilege
When it happens
Trigger: Creating a symlink while running as a non-elevated user without the SeCreateSymbolicLinkPrivilege right (code 1314); target path does not exist so File.directory? guessed wrong flags; target on a remote/unsupported filesystem; sandboxed service accounts (e.g. LocalService) lacking the right.
Common situations: Puppet agent or custom Ruby tools running non-elevated trying to materialize symlink resources; CI workers without Developer Mode; hardening policies that strip SeCreateSymbolicLinkPrivilege from standard users; UAC filtered tokens even for admin-group members.
Related errors
- QueryFullProcessImageNameW(phandle, #{use_win32_path_format}
- ReplaceFile(#{target}, #{source})
- MoveFileEx(#{source}, #{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/de1dcb43ecc144a7.
Report an issue: GitHub.