{"record":{"id":"87080024e0cd9b17","repo":"puppetlabs/puppet","slug":"could-not-call-method-on-indirection","errorCode":null,"errorMessage":"Could not call '%{method}' on '%{indirection}': %{detail}","messagePattern":"Could not call '%(.+?)' on '%(.+?)': %(.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"lib/puppet/indirector/face.rb","lineNumber":53,"sourceCode":"    Puppet::Indirector::Indirection.instances.collect(&:to_s).sort\n  end\n\n  def self.terminus_classes(indirection)\n    Puppet::Indirector::Terminus.terminus_classes(indirection.to_sym).collect(&:to_s).sort\n  end\n\n  def call_indirection_method(method, key, options)\n    begin\n      if method == :save\n        # key is really the instance to save\n        result = indirection.__send__(method, key, nil, options)\n      else\n        result = indirection.__send__(method, key, options)\n      end\n    rescue => detail\n      message = _(\"Could not call '%{method}' on '%{indirection}': %{detail}\") % { method: method, indirection: indirection_name, detail: detail }\n      Puppet.log_exception(detail, message)\n      raise RuntimeError, message, detail.backtrace\n    end\n\n    result\n  end\n\n  action :destroy do\n    summary _(\"Delete an object.\")\n    arguments _(\"<key>\")\n    when_invoked { |key, _options| call_indirection_method :destroy, key, {} }\n  end\n\n  action :find do\n    summary _(\"Retrieve an object by name.\")\n    arguments _(\"[<key>]\")\n    when_invoked do |*args|\n      # Default the key to Puppet[:certname] if none is supplied\n      if args.length == 1\n        key = Puppet[:certname]","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/indirector/face.rb#L35-L71","documentation":"Puppet::Indirector::Face#call_indirection_method is the funnel behind every 'puppet <indirection> <action>' CLI subcommand (facts find, certificate sign, node find, ...). Any exception from the underlying terminus is logged with backtrace and re-raised as RuntimeError 'Could not call <method> on <indirection>: <detail>' — it is a wrapper, and the actionable cause is always the detail text and the logged exception.","triggerScenarios":"puppet facts find node1 --terminus rest when the server is unreachable (wraps the network error); certificate generation with broken SSL state; any terminus rejecting the option combination the face forwarded.","commonSituations":"CLI usage against a misconfigured terminus (facts_terminus=rest with a wrong server setting); running face commands as the wrong user so file or SSL access fails; debugging only from the wrapper message instead of the --trace output.","solutions":["Run the same command with --trace (and --debug) to get the original backtrace logged when the wrapper fired","Fix the named detail cause: terminus setting, connectivity, permissions, or SSL state as indicated","Reproduce outside the face by calling the indirection in Ruby to isolate face-specific option bugs"],"exampleFix":"# before\n$ puppet facts find node1.example.com\n# Error: Could not call 'find' on 'facts': ...\n\n# after\n$ puppet facts find node1.example.com --trace --debug\n# read the original exception; fix facts_terminus/server, then rerun","handlingStrategy":"try-catch","validationCode":"# ruby\n# pre-flight the terminus before invoking the face\nif opts[:terminus] == 'rest'\n  require 'socket'\n  TCPSocket.new(Puppet[:server], Puppet[:serverport]).close\nend\nPuppet::Face[:facts, :current].find(name)","typeGuard":"def indirection_callable?(face_name, method)\n  Puppet::Face[face_name, :current].respond_to?(method)\nend","tryCatchPattern":"begin\n  face.call_indirection_method(method, key, options)\nrescue RuntimeError => e\n  raise unless e.message.start_with?('Could not call')\n  Puppet.err(e.message)  # wrapper text names the method and indirection\n  nil\nend","preventionTips":["Always add --trace on face failures; the wrapper logs the original backtrace","Run face commands as the correct user with valid terminus settings","In scripts needing typed exceptions, call the indirection API directly instead of the face wrapper"],"tags":["puppet-cli","faces","indirector","wrapper-error"],"backgroundTag":"indirection-call-failed","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}