ankane/pghero · error · PgHero::Error

Database not found: #{database_id}

Error message

Database not found: #{database_id}

What it means

unused_indexes(max_scans:, min_size:, across:) can intersect results with other configured databases so only indexes unused everywhere are reported. For each id in the across array it looks the database up in PgHero.databases (keyed by id from pghero.yml); an id with no matching configured database raises PgHero::Error "Database not found: {id}".

Source

Thrown at lib/pghero/methods/indexes.rb:95

            pg_relation_size(i.indexrelid) AS size_bytes,
            idx_scan as index_scans
          FROM
            pg_stat_user_indexes ui
          INNER JOIN
            pg_index i ON ui.indexrelid = i.indexrelid
          WHERE
            NOT indisunique
            AND idx_scan <= :max_scans
            AND pg_relation_size(i.indexrelid) >= :min_size
          ORDER BY
            pg_relation_size(i.indexrelid) DESC,
            relname ASC
        SQL
        result = select_all_size(sql, {max_scans: max_scans.to_i, min_size: min_size.to_i})

        across.each do |database_id|
          database = PgHero.databases.values.find { |d| d.id == database_id }
          raise PgHero::Error, "Database not found: #{database_id}" unless database
          across_result = Set.new(database.unused_indexes(max_scans: max_scans).map { |v| [v[:schema], v[:index]] })
          result.select! { |v| across_result.include?([v[:schema], v[:index]]) }
        end

        result
      end

      def reset_stats
        execute("SELECT pg_stat_reset()")
        true
      end

      def last_stats_reset_time
        select_one <<~SQL
          SELECT
            pg_stat_get_db_stat_reset_time(oid) AS reset_time
          FROM
            pg_database

View on GitHub (pinned to 7edb57986f)

Solutions

  1. Use the exact id from pghero.yml - list valid ids with PgHero.databases.keys in rails console
  2. Validate the across array before calling: across.all? { |id| PgHero.databases.key?(id) }
  3. If a database was renamed, update every caller that references the old id

Example fix

# before - id does not match pghero.yml
db.unused_indexes(across: ["replica"])

# after - use exact key from PgHero.databases
db.unused_indexes(across: ["replica-2"])
Defensive patterns

Strategy: validation

Validate before calling

across = across.select { |id| PgHero.databases.key?(id) }
database.unused_indexes(across: across)

Prevention

When it happens

Trigger: Calling PgHero.database.unused_indexes(across: ["replica"]) when pghero.yml keys that database differently ("replica-2", "reporting"); passing the display name ("Replica") instead of the id; a database removed from pghero.yml while another tool or cached dashboard still requests it.

Common situations: Multi-database pghero setups after renaming keys in pghero.yml; scripts or cron jobs hardcoding database ids; UI links built from stale configuration.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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