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

Failed to convert string SID: %{string_sid}

Error message

Failed to convert string SID: %{string_sid}

What it means

Raised by Puppet::Util::Windows::SID.string_to_sid_ptr when ConvertStringSidToSidW fails to parse the argument into a binary SID. The message embeds the offending input, and Puppet::Util::Windows::Error carries the Win32 code — typically ERROR_INVALID_SID_STRUCTURE (1337) for malformed strings. The yielded pointer is what Win32 APIs expecting PSID consume.

Source

Thrown at lib/puppet/util/windows/sid.rb:193

          end

          sid_string = wide_string_ptr.read_arbitrary_wide_string_up_to(MAXIMUM_SID_STRING_LENGTH)
        end
      end

      sid_string
    end
    module_function :sid_ptr_to_string

    # Convert a SID string, e.g. "S-1-5-32-544" to a pointer (containing the
    # address of the binary SID structure). The returned value can be used in
    # Win32 APIs that expect a PSID, e.g. IsValidSid. The account for this
    # SID may or may not exist.
    def string_to_sid_ptr(string_sid, &block)
      FFI::MemoryPointer.from_string_to_wide_string(string_sid) do |lpcwstr|
        FFI::MemoryPointer.new(:pointer, 1) do |sid_ptr_ptr|
          if ConvertStringSidToSidW(lpcwstr, sid_ptr_ptr) == FFI::WIN32_FALSE
            raise Puppet::Util::Windows::Error, _("Failed to convert string SID: %{string_sid}") % { string_sid: string_sid }
          end

          sid_ptr_ptr.read_win32_local_pointer do |sid_ptr|
            yield sid_ptr
          end
        end
      end

      # yielded sid_ptr has already had LocalFree called, nothing to return
      nil
    end
    module_function :string_to_sid_ptr

    # Return true if the string is a valid SID, e.g. "S-1-5-32-544", false otherwise.
    def valid_sid?(string_sid)
      valid = false

      begin

View on GitHub (pinned to e227c27540)

Solutions

  1. Validate the format first with the library's own helper: Puppet::Util::Windows::SID.valid_sid?('S-1-5-32-544') — it swallows ERROR_INVALID_SID_STRUCTURE and returns false.
  2. Correct the string: must match ^S-\d+-\d+(-\d+){0,13}$ with no trailing dash or spaces.
  3. If the input is an account name, resolve it first via name_to_principal and use principal.sid.
  4. Trim/normalize input from external data sources before conversion.

Example fix

# before
Puppet::Util::Windows::SID.string_to_sid_ptr(maybe_bad_sid) { |ptr| ... }

# after
raise ArgumentError, "bad SID: #{maybe_bad_sid}" unless Puppet::Util::Windows::SID.valid_sid?(maybe_bad_sid)
Puppet::Util::Windows::SID.string_to_sid_ptr(maybe_bad_sid) { |ptr| ... }
Defensive patterns

Strategy: validation

Validate before calling

# validate before converting
SID_PATTERN = /\AS-1-(\d{1,10}-){0,14}\d{1,10}\z/
raise ArgumentError, "malformed SID string: #{sid.inspect}" unless sid.is_a?(String) && sid.match?(SID_PATTERN)

# or use the library helper
return unless Puppet::Util::Windows::SID.valid_sid?(sid)

Type guard

def sid_string?(v)
  v.is_a?(String) && v.match?(/\AS-1-(\d{1,10}-){0,14}\d{1,10}\z/)
end

Try / catch

begin
  Puppet::Util::Windows::SID.string_to_sid_ptr(sid) { |ptr| ... }
rescue Puppet::Util::Windows::Error => e
  raise unless e.code == 1337 # ERROR_INVALID_SID_STRUCTURE
  raise ArgumentError, "invalid SID string: #{sid}"
end

Prevention

When it happens

Trigger: Passing strings like 'S-1-5-32' (missing authority), '1-5-32-544' (no S- prefix), 'S-1-5-32-544-' (trailing dash), values with whitespace or non-numeric sub-authorities, or nil/non-String input; also SIDs with more than the allowed sub-authorities.

Common situations: Manifest or facts data feeding malformed SIDs into ACL management; copy/paste typos in SDDL strings; user data pulled from a CSV/database with stray characters; code passing a fully-qualified account name where the SID string was assumed.

Related errors


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