Fixing uuid-ossp on PostgreSQL 15 (RHEL 8): “extension is not available”

If you’ve ever tried to enable UUID generation in PostgreSQL and hit this:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
ERROR:  extension "uuid-ossp" is not available
DETAIL:  Could not open extension control file "/usr/pgsql-15/share/extension/uuid-ossp.control": No such file or directory.
HINT:  The extension must first be installed on the system where PostgreSQL is running.

…you’re not alone. This is one of those cases where PostgreSQL is telling the truth: the database is fine, but the server OS package that provides the extension files is missing.

And if you’re on a hardened RHEL build, you might run into a second punch in the face:

dnf install postgresql15-contrib
...
requires postgresql15-server = 15.16..., but ...
postgresql15-server ... is filtered out by exclude filtering

This article walks through the exact end-to-end fix on PostgreSQL 15 + RHEL 8, especially when DNF exclude rules block the install.


Why this happens

1) PostgreSQL extensions are “installed” in two layers

  • OS layer: installs extension files (control file + SQL scripts) into the PostgreSQL share directory
    Example path: /usr/pgsql-15/share/extension/
  • Database layer: registers/enables the extension inside a specific database using: CREATE EXTENSION ...

So when PostgreSQL says it can’t find uuid-ossp.control, it means:
✅ You ran the SQL correctly
❌ But the OS package that ships uuid-ossp wasn’t installed

2) On RHEL, uuid-ossp comes from the “contrib” package

For PGDG PostgreSQL 15 installs, that’s typically:

  • postgresql15-contrib

3) The DNF “exclude filtering” block is a repo policy issue

Your error:

postgresql15-server ... is filtered out by exclude filtering

means DNF configuration is blocking that package. This is common when:

  • your org excludes postgresql* to prevent accidental upgrades
  • version locks are enforced
  • the built-in RHEL module stream is being controlled tightly

Step-by-step fix (PostgreSQL 15 on RHEL 8)

Step 1 — Confirm you’re using PGDG Postgres 15 packages

Run:

rpm -qa | egrep -i 'postgresql15|pgdg'
rpm -q postgresql15-server

If you see package names like 15.xx-1PGDG.rhel8.x, you’re on PGDG packaging (which matches your /usr/pgsql-15/... paths).


Step 2 — Find the exclude rule blocking postgresql15-server

Search for excludes:

grep -RIn "exclude=" /etc/dnf /etc/yum.repos.d | grep -i postgres

You’re looking for something like:

  • exclude=postgresql*
  • exclude=postgresql15-server*
  • or a generic rule that catches PGDG packages

Fix it by editing the file that contains the rule and removing/narrowing the exclude line. Example:

sudo vi /etc/dnf/dnf.conf
# remove or adjust exclude=postgresql*

Step 3 — Check for version locks (optional but common)

If the versionlock plugin is used, it can also block installs/upgrades:

dnf versionlock list | grep -i postgresql

To remove locks that block Postgres 15 packages:

sudo dnf versionlock delete postgresql15-server\*
sudo dnf versionlock delete postgresql15\*

Step 4 — Install the missing contrib package

Now install:

sudo dnf install -y postgresql15-contrib

If you need a quick “bypass” without editing config

You can temporarily bypass excludes for a single run:

sudo dnf --disableexcludes=all install -y postgresql15-contrib

If it complains it needs a matching server package, install both:

sudo dnf --disableexcludes=all install -y postgresql15-server postgresql15-contrib

Step 5 — Disable the built-in RHEL PostgreSQL module (recommended for PGDG installs)

This prevents AppStream/module filtering conflicts:

sudo dnf -qy module disable postgresql

Then retry install if needed:

sudo dnf --disableexcludes=all install -y postgresql15-contrib

Step 6 — Restart PostgreSQL (safe practice after package changes)

sudo systemctl restart postgresql-15
sudo systemctl status postgresql-15 --no-pager

Enable uuid-ossp inside the database

Once the OS package is installed, jump into the database and run:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Verify:

SELECT extname, extversion
FROM pg_extension
WHERE extname = 'uuid-ossp';

Test UUID generation:

SELECT uuid_generate_v4();

Using UUIDs in tables (practical pattern)

A clean UUID primary key default:

CREATE TABLE customers (
  id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
  name text NOT NULL,
  created_at timestamptz DEFAULT now()
);

Insert without specifying id:

INSERT INTO customers (name) VALUES ('Example Customer');
SELECT * FROM customers;

Bonus: If you don’t need uuid-ossp, pgcrypto is often simpler

In many environments (especially managed or restricted setups), pgcrypto is easier to enable:

CREATE EXTENSION IF NOT EXISTS pgcrypto;
SELECT gen_random_uuid();

And in tables:

id uuid PRIMARY KEY DEFAULT gen_random_uuid()

If your goal is just “UUID v4 primary keys”, pgcrypto is usually the simplest path.


Key takeaway

When uuid-ossp fails on Postgres 15 with “control file not found,” it’s almost never a PostgreSQL bug. It’s usually:

  1. Missing OS package (postgresql15-contrib)
  2. Repo policy blocks install (DNF exclude filtering / version locks / module streams)

Fix the OS packaging first, then enable the extension inside the database.