{"record":{"id":"22172898e640099c","repo":"puppetlabs/puppet","slug":"invalid-terminus-name-terminus-class","errorCode":null,"errorMessage":"Invalid terminus name %{terminus_class}","messagePattern":"Invalid terminus name %(.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/indirector/indirection.rb","lineNumber":184,"sourceCode":"      end\n    end\n    @terminus_class.value\n  end\n\n  def reset_terminus_class\n    @terminus_class.value = nil\n  end\n\n  # Specify the terminus class to use.\n  def terminus_class=(klass)\n    validate_terminus_class(klass)\n    @terminus_class.value = klass\n  end\n\n  # This is used by terminus_class= and cache=.\n  def validate_terminus_class(terminus_class)\n    unless terminus_class and terminus_class.to_s != \"\"\n      raise ArgumentError, _(\"Invalid terminus name %{terminus_class}\") % { terminus_class: terminus_class.inspect }\n    end\n\n    unless Puppet::Indirector::Terminus.terminus_class(name, terminus_class)\n      raise ArgumentError, _(\"Could not find terminus %{terminus_class} for indirection %{name}\") %\n                           { terminus_class: terminus_class, name: name }\n    end\n  end\n\n  # Expire a cached object, if one is cached.  Note that we don't actually\n  # remove it, we expire it and write it back out to disk.  This way people\n  # can still use the expired object if they want.\n  def expire(key, options = {})\n    request = request(:expire, key, nil, options)\n\n    return nil unless cache? && !request.ignore_cache_save?\n\n    instance = cache.find(request(:find, key, nil, options))\n    return nil unless instance","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/indirector/indirection.rb#L166-L202","documentation":"Indirection#terminus_class= (also used by cache=) validates before storing the setting: a nil or blank terminus name is rejected with ArgumentError 'Invalid terminus name'. Settings such as catalog_terminus = <value> in puppet.conf funnel into this setter, so an empty configuration value explodes here at first use of the indirection.","triggerScenarios":"'catalog_terminus =' or 'node_terminus =' with an empty value in puppet.conf; templated configuration rendering an empty string; Ruby code assigning indirection.terminus_class = nil or ''.","commonSituations":"ERB/EPP templates leaving terminus settings blank 'to use defaults'; Ansible/Puppet-managed puppet.conf with an empty variable interpolated; YAML null coerced to an empty string.","solutions":["Delete the empty <name>_terminus setting so Puppet falls back to the documented default for the run mode.","Set a real terminus name explicitly, e.g. catalog_terminus = compiler on a server, rest on an agent.","When setting programmatically, guard for blank values before assignment.","Verify the effective value afterwards with puppet config print <name>_terminus."],"exampleFix":"# puppet.conf - before\n[agent]\ncatalog_terminus =\n\n# after\n[agent]\n# removed entirely to use the default, or set explicitly:\ncatalog_terminus = rest","handlingStrategy":"validation","validationCode":"def set_terminus!(indirection, name)\n  raise ArgumentError, 'terminus name required' if name.to_s.strip.empty?\n  indirection.terminus_class = name\nend","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Lint managed puppet.conf for empty *_terminus keys.","Use presence checks when templating settings; omit rather than blank.","Verify effective settings with puppet config print after template changes."],"tags":["puppet","indirector","terminus","configuration","empty-value"],"backgroundTag":"invalid-configuration-value","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}