{"record":{"id":"10f69c504ab13dab","repo":"puppetlabs/puppet","slug":"not-authorized-to-call-method-on-description","errorCode":null,"errorMessage":"Not authorized to call %{method} on %{description}","messagePattern":"Not authorized to call %(.+?) on %(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/indirector/indirection.rb","lineNumber":352,"sourceCode":"  # Check authorization if there's a hook available; fail if there is one\n  # and it returns false.\n  def check_authorization(request, terminus)\n    # At this point, we're assuming authorization makes no sense without\n    # client information.\n    return unless request.node\n\n    # This is only to authorize via a terminus-specific authorization hook.\n    return unless terminus.respond_to?(:authorized?)\n\n    unless terminus.authorized?(request)\n      msg = if request.options.empty?\n              _(\"Not authorized to call %{method} on %{description}\") %\n                { method: request.method, description: request.description }\n            else\n              _(\"Not authorized to call %{method} on %{description} with %{option}\") %\n                { method: request.method, description: request.description, option: request.options.inspect }\n            end\n      raise ArgumentError, msg\n    end\n  end\n\n  # Pick the appropriate terminus, check the request's authorization, and return it.\n  # @param [Puppet::Indirector::Request] request instance\n  # @return [Puppet::Indirector::Terminus] terminus instance (usually a subclass\n  #   of Puppet::Indirector::Terminus) for this request\n  def prepare(request)\n    # Pick our terminus.\n    terminus_name = terminus_class\n\n    dest_terminus = terminus(terminus_name)\n    check_authorization(request, dest_terminus)\n    dest_terminus.validate(request)\n\n    dest_terminus\n  end\n","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/indirector/indirection.rb#L334-L370","documentation":"Indirection#prepare calls check_authorization before each request; if the chosen terminus defines authorized? and it returns false, ArgumentError 'Not authorized to call <method> on <description>' is raised (with 'with <options>' appended when request options are present). REST/fileserver termini implement authorized? from the server's authorization config (legacy auth.conf or Puppet Server auth rules), so ACL denials surface through this raise - note it is an ArgumentError, not a Puppet::Error.","triggerScenarios":"An agent requesting a fileserver mount whose allow list does not match its certname; REST calls (file_metadata/file_content finds, report upload, node save) denied by auth.conf path rules; requests from a certificate renamed after the allow rules were written.","commonSituations":"New nodes not added to allow directives; regex metacharacters in certnames breaking allow patterns; legacy auth.conf rule order shadowing an allow; Puppet Server hocon auth rules missing the /puppet/v3 path for an endpoint.","solutions":["Inspect the server's authorization rules (legacy /etc/puppetlabs/puppet/auth.conf or Puppet Server conf.d/auth.conf hocon) and add an allow rule matching the client certname for the denied path.","Check rule ordering - first match wins; make sure your allow precedes broader deny rules.","Verify the client certname (puppet agent --configprint certname) against the allow pattern, remembering '.' is a regex wildcard.","Reload/restart Puppet Server after rule changes and retry with 'puppet agent --test' for verbose output."],"exampleFix":"# legacy auth.conf - before\npath /file_metadata\nauth yes\ndeny *\n\n# after\npath /file_metadata\nauth yes\nallow *.example.com","handlingStrategy":"validation","validationCode":"terminus = indirection.terminus(indirection.terminus_class)\nreq = indirection.request(:find, key, nil, options)\nif terminus.respond_to?(:authorized?) && !terminus.authorized?(req)\n  raise ArgumentError, 'request would be denied by authorization rules'\nend","typeGuard":null,"tryCatchPattern":"begin\n  indirection.find(key, options)\nrescue ArgumentError => e\n  raise if e.message !~ /Not authorized to call/\n  handle_acl_denial(e) # operator action: fix allow rules\nend","preventionTips":["Keep authorization rules in source control and lint them.","Prefer certname-based allow rules over IP rules.","Test ACL changes with a canary node before fleet rollout.","Remember this denial surfaces as ArgumentError, not Puppet::Error."],"tags":["puppet","authorization","auth-conf","acl","rest"],"backgroundTag":"authorization-denied","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}