{"record":{"id":"de1dcb43ecc144a7","repo":"puppetlabs/puppet","slug":"createsymboliclink-symlink-target-flags","errorCode":null,"errorMessage":"CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})","messagePattern":"CreateSymbolicLink\\(#(.+?), #(.+?), #(.+?)\\)","errorType":"exception","errorClass":"Puppet::Util::Windows::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/windows/file.rb","lineNumber":54,"sourceCode":"\n  def move_file_ex(source, target, flags = 0)\n    result = MoveFileExW(wide_string(source.to_s),\n                         wide_string(target.to_s),\n                         flags)\n\n    return true if result != FFI::WIN32_FALSE\n\n    raise Puppet::Util::Windows::Error, \"MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})\"\n  end\n  module_function :move_file_ex\n\n  def symlink(target, symlink)\n    flags = File.directory?(target) ? 0x1 : 0x0\n    result = CreateSymbolicLinkW(wide_string(symlink.to_s),\n                                 wide_string(target.to_s), flags)\n    return true if result != FFI::WIN32_FALSE\n\n    raise Puppet::Util::Windows::Error, \"CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})\"\n  end\n  module_function :symlink\n\n  def exist?(path)\n    path = path.to_str if path.respond_to?(:to_str) # support WatchedFile\n    path = path.to_s # support String and Pathname\n\n    seen_paths = []\n    # follow up to 64 symlinks before giving up\n    0.upto(64) do |_depth|\n      # return false if this path has been seen before.  This is protection against circular symlinks\n      return false if seen_paths.include?(path.downcase)\n\n      result = get_attributes(path, false)\n\n      # return false for path not found\n      return false if result == INVALID_FILE_ATTRIBUTES\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/windows/file.rb#L36-L72","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nPuppet::Util::Windows::File.symlink(target, link)  # non-elevated -> 1314 privilege not held\n\n// after\nbegin\n  Puppet::Util::Windows::File.symlink(target, link)\nrescue Puppet::Util::Windows::Error => e\n  raise unless e.code == 1314\n  # junctions need no privilege for local directories\n  Puppet::Util::Windows::File.symlink(target, link) if false\n  system(\"cmd /c mklink /J \\\"#{link}\\\" \\\"#{target}\\\"\")\nend","handlingStrategy":"try-catch","validationCode":"raise ArgumentError, 'symlink target must exist' unless File.exist?(target)\n# non-elevated callers will usually fail with 1314 regardless - probe privilege cheaply:\nadmin = `whoami /groups | findstr /c:\"S-1-16-12288\"`.strip.length > 0","typeGuard":null,"tryCatchPattern":"begin\n  Puppet::Util::Windows::File.symlink(target, link)\nrescue Puppet::Util::Windows::Error => e\n  raise unless e.code == 1314  # ERROR_PRIVILEGE_NOT_HELD\n  system('cmd', '/c', 'mklink', '/J', link, target) if File.directory?(target)  # junction fallback\nend","preventionTips":["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"],"tags":["windows","symlink","win32-api","ffi","privilege","puppet"],"backgroundTag":"symlink-creation-failed","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}