ankane/pghero · error · PgHero::Error

Spec not found: #{config["spec"]}

Error message

Spec not found: #{config["spec"]}

What it means

When a database entry in pghero.yml has "spec" but no "url", build_connection_model resolves the spec against ActiveRecord::Base.configurations (database.yml) using configs_for(env_name: PgHero.env, name: spec, include_hidden: true). If no configuration matches that name in the current environment, PgHero raises Error "Spec not found: {name}" at database construction time.

Source

Thrown at lib/pghero/database.rb:144

        unless @connection_model.connection_db_config.adapter.to_s.match?(/postg/i)
          raise Error, "Invalid connection URL"
        end
        @adapter_checked = true
      end

      @connection_model
    end

    # just return the model
    # do not start a connection
    def build_connection_model
      url = config["url"]

      # resolve spec
      if !url && config["spec"]
        config_options = {env_name: PgHero.env, name: config["spec"], include_hidden: true}
        resolved = ActiveRecord::Base.configurations.configs_for(**config_options)
        raise Error, "Spec not found: #{config["spec"]}" unless resolved
        url = resolved.configuration_hash
      end

      url = url.dup

      Class.new(PgHero::Connection) do
        def self.name
          "PgHero::Connection::Database#{object_id}"
        end

        case url
        when String
          url = "#{url}#{url.include?("?") ? "&" : "?"}connect_timeout=5" unless url.include?("connect_timeout=")
        when Hash
          url[:connect_timeout] ||= 5
        end
        establish_connection url if url
      end

View on GitHub (pinned to 7edb57986f)

Solutions

  1. Make the spec value match a database.yml configuration name exactly for the current environment
  2. Or bypass spec resolution with an explicit url: postgres://user:pass@host:5432/dbname in pghero.yml
  3. Check the environment: print PgHero.env and ActiveRecord::Base.configurations.configs_for(env_name: PgHero.env, include_hidden: true).map(&:name) in rails console

Example fix

# config/pghero.yml - before
databases:
  main:
    spec: primary

# after - match database.yml entry name exactly, or use a url
databases:
  main:
    url: postgres://user:pass@host:5432/dbname
Defensive patterns

Strategy: validation

Validate before calling

# verify every spec resolves before pghero builds its databases
PgHero.config.fetch("databases", {}).each do |id, db_config|
  next if db_config["url"] || !db_config["spec"]
  resolved = ActiveRecord::Base.configurations.configs_for(env_name: PgHero.env, name: db_config["spec"], include_hidden: true)
  raise "pghero spec '#{db_config["spec"]}' (database #{id}) not found in database.yml for #{PgHero.env}" unless resolved
end

Prevention

When it happens

Trigger: pghero.yml says spec: "primary" but database.yml names the entry differently (or only defines it under another env); RAILS_ENV/RACK_ENV differs between the environment that generated pghero.yml and the running one; a renamed or removed database config after a multi-database refactor. Note PgHero's default config derives spec names from database.yml automatically, so this usually appears after hand-editing.

Common situations: Rails 6+ three-tier database.yml where the same logical name exists only in some environments; promoting config from development to production; replicas/hidden configs where the name must match exactly (include_hidden covers visibility, not naming).

Related errors


AI-assisted analysis of ankane/pghero@7edb57986f (2026-08-21). Data as JSON: /api/errors/8b71b7ea75908f6c. Report an issue: GitHub.