{"record":{"id":"470ff779578e75c2","repo":"puppetlabs/puppet","slug":"type-mismatch-expect-rtype-but-type-present","errorCode":null,"errorMessage":"Type mismatch (expect %{rtype} but %{type} present)","messagePattern":"Type mismatch \\(expect %(.+?) but %(.+?) present\\)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/windows/registry.rb","lineNumber":235,"sourceCode":"    # type is value type. (see Win32::Registry::Constants module)\n    # data is value data, its class is:\n    # :REG_SZ, REG_EXPAND_SZ\n    #    String\n    # :REG_MULTI_SZ\n    #    Array of String\n    # :REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD\n    #    Integer\n    # :REG_BINARY\n    #    String (contains binary data)\n    #\n    # When rtype is specified, the value type must be included by\n    # rtype array, or TypeError is raised.\n    def read(key, name_ptr, *rtype)\n      result = nil\n\n      query_value_ex(key, name_ptr) do |type, data_ptr, byte_length|\n        unless rtype.empty? or rtype.include?(type)\n          raise TypeError, _(\"Type mismatch (expect %{rtype} but %{type} present)\") % { rtype: rtype.inspect, type: type }\n        end\n\n        string_length = 0\n        # buffer is raw bytes, *not* chars - less a NULL terminator\n        string_length = (byte_length / WCHAR_SIZE) - 1 if byte_length > 0\n\n        begin\n          result = case type\n                   when Win32::Registry::REG_SZ, Win32::Registry::REG_EXPAND_SZ\n                     [type, data_ptr.read_wide_string(string_length, Encoding::UTF_8, true)]\n                   when Win32::Registry::REG_MULTI_SZ\n                     [type, data_ptr.read_wide_string(string_length).split(/\\0/)]\n                   when Win32::Registry::REG_BINARY\n                     [type, data_ptr.read_bytes(byte_length)]\n                   when Win32::Registry::REG_DWORD\n                     [type, data_ptr.read_dword]\n                   when Win32::Registry::REG_DWORD_BIG_ENDIAN\n                     [type, data_ptr.order(:big).read_dword]","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/windows/registry.rb#L217-L253","documentation":"Raised by Registry.read (lib/puppet/util/windows/registry.rb:235) when the caller restricted acceptable types via the rtype splat but the value's actual registry type is not in that list — e.g. read(key, name, Win32::Registry::REG_DWORD) over a REG_SZ value. The check runs before decoding (the method returns [type, data]), so nothing is read in the failing case; it is a TypeError, not a Win32 error.","triggerScenarios":"Passing rtype constants that exclude the stored type; installers writing REG_EXPAND_SZ where REG_SZ was declared; string-stored numbers ('1') read as REG_DWORD; values changed outside Puppet between runs; 32/64-bit registry views (KEY_WOW64_32KEY/64KEY) holding different types under the same path.","commonSituations":"registry_value manifests drifting from reality after manual edits or installer runs; installers switching REG_SZ to REG_EXPAND_SZ; WOW6432NODE redirection surprises.","solutions":["Call read once without rtype to learn the stored type (first element of the returned pair), then decide how to handle it.","Accept the legitimate alternatives in one call: read(key, name, Win32::Registry::REG_SZ, Win32::Registry::REG_EXPAND_SZ).","Re-write the value in the expected type (reg.exe add ... /t REG_DWORD /f) if it must be managed as that type.","In manifests, make the declared registry_value type match what the provider writes, and check the registry view so you read the intended bitness."],"exampleFix":"# before — hard expectation of DWORD\nread(key, name_ptr, Win32::Registry::REG_DWORD)\n\n# after — accept string-stored numbers and coerce\ntype, data = read(key, name_ptr, Win32::Registry::REG_DWORD, Win32::Registry::REG_SZ)\ndata = data.to_i if type == Win32::Registry::REG_SZ","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"# narrow before the typed read — read without rtype returns [type, data]\ntype, _data = Registry.read(key, name)\nexpected = Win32::Registry::REG_DWORD\nif type != expected\n  Puppet.debug \"#{name} stored as #{type}, expected #{expected}\"\n  # caller branches before attempting a typed read\nend","tryCatchPattern":"begin\n  type, data = read(key, name, *expected_types)\nrescue TypeError => e\n  Puppet.err \"#{key.keyname}\\\\#{name}: #{e.message}\"\n  type, data = read(key, name) # fall back to unrestricted read\nend","preventionTips":["Read unrestricted first whenever the stored type is not guaranteed","List all acceptable types in rtype instead of a single one","Audit registry manifests against actual values after installer updates","Mind the WOW64 registry view when types differ between bitness"],"tags":["windows","registry","type-mismatch","typeerror","puppet"],"backgroundTag":"registry-value-type-mismatch","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}