{"record":{"id":"be0b8514fd2a702d","repo":"puppetlabs/puppet","slug":"resource-instance-does-not-match-request-key","errorCode":null,"errorMessage":"Resource instance does not match request key","messagePattern":"Resource instance does not match request key","errorType":"validation","errorClass":"Puppet::Indirector::ValidationError","httpStatus":null,"severity":"error","filePath":"lib/puppet/indirector/resource/validator.rb","lineNumber":7,"sourceCode":"# frozen_string_literal: true\n\nmodule Puppet::Resource::Validator\n  def validate_key(request)\n    type, title = request.key.split('/', 2)\n    unless type.casecmp(request.instance.type).zero? and title == request.instance.title\n      raise Puppet::Indirector::ValidationError, _(\"Resource instance does not match request key\")\n    end\n  end\nend\n","sourceCodeStart":1,"sourceCodeEnd":11,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/indirector/resource/validator.rb#L1-L11","documentation":"Puppet::Resource::Validator#validate_key enforces that a resource request's key 'Type/Title' matches the attached resource instance: type must match case-insensitively (String#casecmp == 0) and title must match exactly. Any divergence raises Puppet::Indirector::ValidationError. It guards save/search paths of the resource indirection so a request cannot write an instance under a different type/title than the key it declares.","triggerScenarios":"Building a Puppet::Resource::Request (or calling Puppet::Resource.indirection.save) with key 'service/httpd' but an instance of type :service titled 'nginx', or 'File[/tmp/a]' saved under key 'file//tmp/b'; also mismatched title case ('Web01' vs 'web01') since title comparison is exact.","commonSituations":"Custom report/inspection tools that re-key resources (e.g., normalizing titles to lowercase) before saving; copy-paste of request construction where key and instance come from different sources; refactoring resource titles with capitalization changes while reusing cached keys.","solutions":["Derive the key from the instance itself instead of composing it separately: \"#{resource.type}/#{resource.title}\"","Recreate the request after mutating a resource's title/type so key and instance stay in lockstep","Remember title matching is case-sensitive while type matching is not; align title strings exactly","In tests/factories, always build requests via Puppet::Resource.indirection.request(:save, res.ref, res)"],"exampleFix":"# before\nres = Puppet::Resource.new(:service, 'httpd')\nreq = Puppet::Resource.indirection.request(:save, 'service/nginx', res)\nreq.validate  # => ValidationError: Resource instance does not match request key\n\n# after\nreq = Puppet::Resource.indirection.request(:save, \"#{res.type}/#{res.title}\", res)\nreq.validate  # passes","handlingStrategy":"validation","validationCode":"type, title = request.key.split('/', 2)\nreturn unless request.instance\nunless type.casecmp(request.instance.type).zero? && title == request.instance.title\n  raise Puppet::Indirector::ValidationError, 'key/type/title drift detected before save'\nend","typeGuard":"def resource_matches_key?(resource, key)\n  type, title = key.split('/', 2)\n  type.casecmp(resource.type).zero? && title == resource.title\nend","tryCatchPattern":null,"preventionTips":["Derive request keys from resource.ref (\"#{type}/#{title}\") instead of composing strings","Never mutate a resource's title between building the key and saving","Unit-test save paths with resources whose titles contain spaces/case to catch drift"],"tags":["puppet","resource","validation","key-mismatch"],"backgroundTag":"request-key-mismatch","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}