puppetlabs/puppet · error · Puppet::Error

manifest of environment '#

Error message

manifest of environment '#{@environment.name}' appoints '#{file}'. It does not exist

What it means

Companion guard to the directory check in Loaders#load_environment: the manifest path from environment.conf is neither NO_MANIFEST, nor a directory, nor an existing file, so File.exist?(file) is false and Puppet::Error is raised. The appointed manifest file simply is not on disk at that path.

Solutions

  1. Create the missing file at the exact path shown in the message.
  2. Fix the path in environment.conf — relative paths resolve against the environment root, so verify with `ls environments/<env>/<path>`.
  3. If the environment has no manifest, set the manifest setting to no_manifest explicitly.

Example fix

# environment.conf: manifest = manifests/site.pp
# before: environments/production/manifests/ is empty or missing site.pp
# after: create environments/production/manifests/site.pp containing at minimum:
#   node default { }
Defensive patterns

Strategy: validation

Validate before calling

# Ensure the appointed manifest exists before deploy
env_root = 'environments/production'
manifest = File.foreach(File.join(env_root, 'environment.conf'))
                    .map { |l| l[/^\s*manifest\s*=\s*(\S+)/, 1] }.compact.first
if manifest && manifest != 'no_manifest'
  path = File.expand_path(manifest, env_root)
  raise "manifest '#{path}' does not exist" unless File.exist?(path)
end

Prevention

When it happens

Trigger: environment.conf `manifest = manifests/site.pp` but the file was never created, was deleted, or the path is relative to a different base than expected; typo in the path; deploy pipeline skipped copying manifests.

Common situations: Control repo deploy that copied hiera data but not manifests; branch where site.pp was moved; CI validating an environment before manifests are rendered.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/ce23531c01397e1b. Report an issue: GitHub.

Appendix: source

Thrown at lib/puppet/pops/loaders.rb:302

  # @return [Model::Program] The manifest parsed into a model object
  def load_main_manifest
    parser = Parser::EvaluatingParser.singleton
    parsed_code = Puppet[:code]
    program = if parsed_code != ""
                parser.parse_string(parsed_code, 'unknown-source-location')
              else
                file = @environment.manifest

                # if the manifest file is a reference to a directory, parse and
                # combine all .pp files in that directory
                if file == Puppet::Node::Environment::NO_MANIFEST
                  nil
                elsif File.directory?(file)
                  raise Puppet::Error, "manifest of environment '#{@environment.name}' appoints directory '#{file}'. It must be a file"
                elsif File.exist?(file)
                  parser.parse_file(file)
                else
                  raise Puppet::Error, "manifest of environment '#{@environment.name}' appoints '#{file}'. It does not exist"
                end
              end
    instantiate_definitions(program, public_environment_loader) unless program.nil?
    program
  rescue Puppet::ParseErrorWithIssue => detail
    detail.environment = @environment.name
    raise
  rescue => detail
    msg = _('Could not parse for environment %{env}: %{detail}') % { env: @environment, detail: detail }
    error = Puppet::Error.new(msg)
    error.set_backtrace(detail.backtrace)
    raise error
  end

  # Add 4.x definitions found in the given program to the given loader.
  def instantiate_definitions(program, loader)
    program.definitions.each { |d| instantiate_definition(d, loader) }
    nil

View on GitHub (pinned to e227c27540)