puppetlabs/puppet · error · Puppet::Util::Windows::Error
Invalid SID
Error message
Invalid SID
What it means
Raised by Puppet::Util::Windows::SID.sid_ptr_to_string when the argument is not an FFI::Pointer or IsValidSid rejects the binary SID at that address (malformed Revision, SubAuthorityCount, or IdentifierAuthority). The method otherwise converts the binary SID to string form ('S-1-5-32-544') via ConvertSidToStringSidW. This is a data validation failure on the in-memory SID structure.
Source
Thrown at lib/puppet/util/windows/sid.rb:163
sid_bytes = ptr.read_array_of_uchar(get_length_sid(ptr))
end
rescue Puppet::Util::Windows::Error => e
raise if e.code != ERROR_INVALID_SID_STRUCTURE
end
Principal.lookup_account_sid(sid_bytes).domain_account
rescue
nil
end
module_function :sid_to_name
# https://stackoverflow.com/a/1792930 - 68 bytes, 184 characters in a string
MAXIMUM_SID_STRING_LENGTH = 184
# Convert a SID pointer to a SID string, e.g. "S-1-5-32-544".
def sid_ptr_to_string(psid)
if !psid.is_a?(FFI::Pointer) || IsValidSid(psid) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, _("Invalid SID")
end
sid_string = nil
FFI::MemoryPointer.new(:pointer, 1) do |buffer_ptr|
if ConvertSidToStringSidW(psid, buffer_ptr) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, _("Failed to convert binary SID")
end
buffer_ptr.read_win32_local_pointer do |wide_string_ptr|
if wide_string_ptr.null?
raise Puppet::Error, _("ConvertSidToStringSidW failed to allocate buffer for sid")
end
sid_string = wide_string_ptr.read_arbitrary_wide_string_up_to(MAXIMUM_SID_STRING_LENGTH)
end
end
sid_stringView on GitHub (pinned to e227c27540)
Solutions
- Use the higher-level helper for byte arrays: Puppet::Util::Windows::SID.octet_string_to_sid_string(bytes) instead of a raw pointer.
- Ensure the pointer is an FFI::Pointer still alive in scope (keep the MemoryPointer block open while reading).
- Verify offset/length when extracting SIDs from structs (GetSidSubAuthorityCount, GetLengthSid) before converting.
- Dump the bytes (ptr.read_bytes(GetLengthSid(ptr))) and check Revision (first byte == 1) and sane SubAuthorityCount (<= 15).
Example fix
# before sid_string = Puppet::Util::Windows::SID.sid_ptr_to_string(sid_bytes) # sid_bytes is an Array # after sid_string = Puppet::Util::Windows::SID.octet_string_to_sid_string(sid_bytes)
Defensive patterns
Strategy: type-guard
Validate before calling
# simplest pre-check: pointer is alive and the bytes look like a SID ok = ptr.is_a?(FFI::Pointer) && !ptr.null? && ptr.read_uint8 == 1 && ptr.get_uint8(1) <= 15 raise ArgumentError, 'not a valid SID pointer' unless ok
Type guard
def sid_pointer?(obj) obj.is_a?(FFI::Pointer) && !obj.null? end raise TypeError, 'expected FFI::Pointer to a SID' unless sid_pointer?(ptr)
Try / catch
begin Puppet::Util::Windows::SID.sid_ptr_to_string(ptr) rescue Puppet::Util::Windows::Error => e raise unless e.code == 1337 # ERROR_INVALID_SID_STRUCTURE raise 'SID buffer malformed - check offsets and buffer lifetime' end
Prevention
- Keep FFI::MemoryPointer blocks open for the whole duration you read from them — pointers outlive their blocks only as dangling addresses.
- Prefer octet_string_to_sid_string for Array-of-bytes input instead of hand-managing pointers.
- Validate Revision (byte 0 == 1) and SubAuthorityCount (byte 1 <= 15) when walking raw SID buffers.
When it happens
Trigger: Passing a Ruby String or Array of bytes instead of an FFI::Pointer; reading a SID from a struct/buffer with the wrong offset or truncated length so the bytes at the address are not a valid SID; using a freed FFI::MemoryPointer after its block exited (dangling pointer).
Common situations: Hand-rolled FFI code parsing TOKEN_USER or SECURITY_DESCRIPTOR buffers with wrong offsets; SIDs copied byte-wise into an undersized buffer; memory blocks used after the MemoryPointer block closes; misuse where octet_string_to_sid_string (which takes byte arrays) was the intended entry point.
Related errors
- Failed to call LookupAccountNameW with account: %{account_na
- Byte array for lookup_account_sid must not be nil and must b
- Failed to call LookupAccountSidW with bytes: %{sid_bytes}
- Invalid SID
- Octet string must be an array of bytes
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/29bd4f4b24569b5d.
Report an issue: GitHub.